| Server IP : 180.180.241.3 / Your IP : 216.73.216.216 Web Server : Microsoft-IIS/7.5 System : Windows NT NETWORK-NHRC 6.1 build 7601 (Windows Server 2008 R2 Standard Edition Service Pack 1) i586 User : IUSR ( 0) PHP Version : 5.3.28 Disable Function : NONE MySQL : ON | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : C:/Program Files/Microsoft SQL Server/MSSQL11.MSSQLSERVER/MSSQL/Install/ |
Upload File : |
/**********************************************************************/
/* PRE_MSDB.SQL */
/* */
/* Prepares MSDB for upgrade. */
/* */
/*
** Copyright (c) Microsoft Corporation
** All Rights Reserved.
*/
/**********************************************************************/
PRINT '----------------------------------'
PRINT 'Starting execution of PRE_MSDB.SQL'
PRINT '----------------------------------'
use msdb
go
-- If the user sets implicit_transactions on, some specprocs and DBCC commands will fail
-- Need to save the state and disable implicit_transactions
DECLARE @implicit_transactions_flag INT
DECLARE @is_implicit_transactions_set BIT
SELECT @is_implicit_transactions_set = CONVERT(BIT, value)
FROM fn_listextendedproperty(N'IMPLICIT_TRANSACTIONS', default, default, default, default, default, default);
IF (@is_implicit_transactions_set IS NOT NULL)
BEGIN
EXEC sp_dropextendedproperty N'IMPLICIT_TRANSACTIONS'
END
SET @implicit_transactions_flag = 2
SET @is_implicit_transactions_set = @@options & @implicit_transactions_flag
EXEC sp_addextendedproperty
@name = N'IMPLICIT_TRANSACTIONS', @value = @is_implicit_transactions_set
SET IMPLICIT_TRANSACTIONS OFF
--set compatibily level to 100
EXEC sp_dbcmptlevel @dbname = 'msdb', @new_cmptlevel = '100'
GO
/**********************************************************************/
/* PRE_SQLAGENT100.SQL */
/* */
/* Upgrades 7.x, 8.x and 9.0 to 10.0 and drops all obsolete 8.x */
/* */
/*
** Copyright (c) Microsoft Corporation
** All Rights Reserved.
*/
/**********************************************************************/
PRINT '-----------------------------------------'
PRINT 'Starting execution of PRE_SQLAGENT100.SQL'
PRINT '-----------------------------------------'
use msdb
go
-- Check that we're in msdb
IF (DB_NAME() <> N'msdb')
RAISERROR('A problem was encountered accessing msdb. upgrade script terminating.', 20, 127) WITH LOG
go
CHECKPOINT
go
--set compatibily level to 110
ALTER DATABASE msdb
SET COMPATIBILITY_LEVEL = 110
GO
-- Allow updates to system catalogs so that we can fully manipulate our system objects
EXECUTE master.dbo.sp_configure N'allow updates', 1
go
RECONFIGURE WITH OVERRIDE
go
/**************************************************************/
/* Record time of start of creates */
/**************************************************************/
SELECT start = getdate() INTO #InstMsdb
go
--preserve existing object permnission during upgrade
--create perms table
IF (NOT OBJECT_ID(N'dbo.upgrade_perms', 'U') IS NULL)
BEGIN
DROP TABLE dbo.upgrade_perms
END
-- upgrade_perms is filled with current permission of objects in MSDB
-- the structure of table is:
-- state_desc = GRANT|DENY
-- permission_name = SELECT|EXECUTE|UPDATE ...
-- object_name = grantor name
-- grantee_name = grantee name
CREATE TABLE dbo.upgrade_perms(state_desc nvarchar(60), permission_name sysname, object_name sysname, grantee_name sysname)
CREATE INDEX indnc ON dbo.upgrade_perms(object_name)
DECLARE @state_desc nvarchar(60)
DECLARE @permission_name sysname
DECLARE @object_name sysname
DECLARE @grantee_name sysname
DECLARE perms_cursor CURSOR LOCAL FOR
SELECT state_desc, permission_name, OBJECT_NAME(major_id), USER_NAME(grantee_principal_id) from msdb.sys.database_permissions
WHERE state_desc IS NOT NULL AND
permission_name IS NOT NULL AND
OBJECT_NAME(major_id) IS NOT NULL AND
USER_NAME(grantee_principal_id) IS NOT NULL
OPEN perms_cursor
FETCH NEXT FROM perms_cursor INTO @state_desc, @permission_name, @object_name, @grantee_name
WHILE (@@fetch_status = 0)
BEGIN
INSERT dbo.upgrade_perms(state_desc, permission_name, object_name, grantee_name)
VALUES(@state_desc, @permission_name, @object_name, @grantee_name)
FETCH NEXT FROM perms_cursor INTO @state_desc, @permission_name, @object_name, @grantee_name
END
DEALLOCATE perms_cursor
go
------------------------VIEWS UPGRADE---------------------------------------
------------------------TABLE UPGRADE---------------------------------------
--create an populate sysoriginatingservers
use msdb
go
IF (NOT EXISTS (SELECT * --just a safe belt, this table shouldn't be in 8.x
FROM msdb.dbo.sysobjects
WHERE (name = N'sysoriginatingservers')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysoriginatingservers...'
CREATE TABLE dbo.sysoriginatingservers
(
-- There is only a single MSX server record in this table (originating_server_id = 1)
-- 0 is generated by sysoriginatingservers_view and indicates the local server
originating_server_id INT CONSTRAINT CK_originating_server_id_MustBe_1 CHECK (originating_server_id = 1)
DEFAULT (1) UNIQUE CLUSTERED,
originating_server sysname NOT NULL UNIQUE NONCLUSTERED,
--Mark this record as a MSX server entry
master_server bit CONSTRAINT CK_master_server_MustBe_1 CHECK (master_server = 1)
DEFAULT (1)
)
END
go
IF (NOT EXISTS (SELECT t.name FROM msdb.sys.all_columns c JOIN msdb.sys.all_objects t
ON c.object_id = t.object_id
WHERE c.name = 'originating_server_id' and t.name = 'sysjobs' and t.type = 'U'))
BEGIN
PRINT ''
PRINT 'Adding column originating_server_id to table sysjobs...'
--add new column 9.0 originating_server_id
ALTER TABLE sysjobs WITH NOCHECK
ADD originating_server_id INT NULL
END
go
DECLARE @MSXServerName sysname
DECLARE @LocalServerName sysname
DECLARE @UpdateOrgServerTSQL nvarchar(MAX)
SELECT @LocalServerName = UPPER(CONVERT(sysname, SERVERPROPERTY('servername')))
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServerName',
@MSXServerName OUTPUT,
N'no_output'
SELECT @MSXServerName = LTRIM(RTRIM(UPPER(@MSXServerName)))
IF (@MSXServerName = '') SELECT @MSXServerName = NULL
IF (@MSXServerName IS NOT NULL)
BEGIN
IF (NOT EXISTS( SELECT * FROM dbo.sysoriginatingservers
WHERE originating_server_id = 1 AND originating_server = @MSXServerName
AND master_server = 1))
BEGIN
PRINT ''
PRINT 'Populate table sysoriginatingservers...'
INSERT INTO sysoriginatingservers( originating_server_id, originating_server, master_server)
VALUES(1, @MSXServerName, 1)
END
END
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysjobs')
AND (type = 'U')))
BEGIN
IF (EXISTS (SELECT t.name FROM msdb.sys.all_columns c JOIN msdb.sys.all_objects t
ON c.object_id = t.object_id
WHERE c.name = 'originating_server' and t.name = 'sysjobs' and t.type = 'U'))
BEGIN
PRINT ''
PRINT 'Populate new column originating_server_id of table sysjobs...'
--set this column based on the value of 8.0 only column originating_server
--if MSX server is NULL we come up with server name that cannot exit, a generated GUID
SELECT @UpdateOrgServerTSQL =
'
UPDATE sysjobs SET originating_server_id =
CASE UPPER(originating_server)
WHEN ''' + @LocalServerName + ''' THEN 0 --local_server_id
WHEN ''' + ISNULL(@MSXServerName, CONVERT(sysname, NEWID())) + ''' THEN 1 --msx_server_id
ELSE 0 --7.0 (local) or bad data
END
'
EXECUTE( @UpdateOrgServerTSQL)
PRINT ''
PRINT 'Drop column originating_server of table sysjobs...'
--drop 8.0 column originating_server
DROP INDEX sysjobs.nc2
ALTER TABLE sysjobs DROP COLUMN originating_server
END
END
go
--normalize 8.0 sysjobschedules into 9.0 sysschedules and sysjobschedules
IF NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysschedules')
AND (type = 'U'))
BEGIN
--create first sysschedules table
PRINT ''
PRINT 'Creating table sysschedules...'
CREATE TABLE dbo.sysschedules
(
schedule_id INT IDENTITY PRIMARY KEY CLUSTERED,
schedule_uid UNIQUEIDENTIFIER NOT NULL,
originating_server_id INT NOT NULL,
name sysname NOT NULL,
owner_sid varbinary(85) NOT NULL,
enabled INT NOT NULL,
freq_type INT NOT NULL,
freq_interval INT NOT NULL,
freq_subday_type INT NOT NULL,
freq_subday_interval INT NOT NULL,
freq_relative_interval INT NOT NULL,
freq_recurrence_factor INT NOT NULL,
active_start_date INT NOT NULL,
active_end_date INT NOT NULL,
active_start_time INT NOT NULL,
active_end_time INT NOT NULL,
date_created DATETIME NOT NULL DEFAULT (GETDATE()),
date_modified DATETIME NOT NULL DEFAULT (GETDATE()),
version_number INT NOT NULL DEFAULT (1)
)
-- CREATE UNIQUE CLUSTERED INDEX clust ON sysschedules(job_id, name)
-- CREATE UNIQUE NONCLUSTERED INDEX nc1 ON sysschedules(schedule_id)
END
go
--a system object cannot be renamed, turn off marking system object trace to alloe renaming of temp_sysjobschedules
dbcc traceoff(1717, -1)
go
-- create temp cross 9.0 table temp_sysjobschedules
IF EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'temp_sysjobschedules')
AND (type = 'U'))
BEGIN
DROP TABLE dbo.temp_sysjobschedules
END
go
PRINT ''
PRINT 'Creating table temp_sysjobschedules'
CREATE TABLE dbo.temp_sysjobschedules
(
schedule_id INT REFERENCES dbo.sysschedules(schedule_id),
job_id UNIQUEIDENTIFIER REFERENCES dbo.sysjobs(job_id),
next_run_date INT NOT NULL DEFAULT 0,
next_run_time INT NOT NULL DEFAULT 0
)
go
DECLARE @dynamicSQL nvarchar(4000)
IF (EXISTS (SELECT t.name FROM msdb.sys.all_columns c JOIN msdb.sys.all_objects t
ON c.object_id = t.object_id
WHERE c.name = 'name' and t.name = 'sysjobschedules' and t.type = 'U'))
BEGIN
PRINT ''
PRINT 'Moving schedule data ...'
SET IDENTITY_INSERT dbo.sysschedules ON
SELECT @dynamicSQL =
'
INSERT INTO dbo.sysschedules
(
schedule_id ,
schedule_uid ,
originating_server_id ,
name ,
owner_sid ,
enabled ,
freq_type ,
freq_interval ,
freq_subday_type ,
freq_subday_interval ,
freq_relative_interval ,
freq_recurrence_factor ,
active_start_date ,
active_end_date ,
active_start_time ,
active_end_time ,
date_created
)
SELECT
js.schedule_id ,
NEWID() ,
0 , --local server. TO DO make sure local server = 0
js.name ,
j.owner_sid ,
js.enabled ,
js.freq_type ,
js.freq_interval ,
js.freq_subday_type ,
js.freq_subday_interval ,
js.freq_relative_interval ,
js.freq_recurrence_factor ,
js.active_start_date ,
js.active_end_date ,
js.active_start_time ,
js.active_end_time ,
js.date_created
FROM
dbo.sysjobs j JOIN dbo.sysjobschedules js ON j.job_id = js.job_id
INSERT INTO dbo.temp_sysjobschedules
(
schedule_id ,
job_id ,
next_run_date ,
next_run_time
)
SELECT
js.schedule_id ,
js.job_id ,
js.next_run_date ,
js.next_run_time
FROM dbo.sysjobs j JOIN dbo.sysjobschedules js ON j.job_id = js.job_id
'
EXECUTE (@dynamicSQL)
SET IDENTITY_INSERT dbo.sysschedules OFF
IF (EXISTS (SELECT *
FROM msdb.dbo.syscolumns
WHERE (id = OBJECT_ID(N'sysjobschedules'))
AND (name = N'date_created')
AND (cdefault <> 0)))
EXECUTE sp_unbindefault N'sysjobschedules.date_created'
DROP TABLE dbo.sysjobschedules
EXECUTE sp_rename 'temp_sysjobschedules', 'sysjobschedules'
EXECUTE (N'CREATE UNIQUE CLUSTERED INDEX clust ON dbo.sysjobschedules(job_id, schedule_id)')
PRINT ''
PRINT 'Updating schedules done'
END
go
--just a safe belt
IF EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'temp_sysjobschedules')
AND (type = 'U'))
BEGIN
DROP TABLE dbo.temp_sysjobschedules
END
go
--alter only if command column is not already nvarchar(max)
IF (NOT EXISTS (SELECT c.* FROM msdb.sys.all_columns c JOIN msdb.sys.all_objects t
ON c.object_id = t.object_id
WHERE (c.name = 'proxy_id' OR c.name = 'step_uid') AND t.name = 'sysjobsteps' AND t.type = 'U'))
BEGIN
PRINT ''
PRINT 'Adding proxy_id, step_uid columns to sysjobsteps table'
ALTER TABLE sysjobsteps ADD
proxy_id INT NULL,
step_uid UNIQUEIDENTIFIER NULL
END
go
--rename DTS subsystem to SSIS
IF (OBJECT_ID('dbo.sysjobsteps', 'U') IS NOT NULL)
BEGIN
UPDATE dbo.sysjobsteps SET subsystem = N'SSIS' WHERE UPPER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'DTS'
END
go
--to be safer populate sysjobsteps with guids, otherwise step table logs are not possible
EXECUTE (N'UPDATE sysjobsteps SET step_uid = NEWID() WHERE step_uid IS NULL')
go
--if there is no index for step_uid, create it, so step table logs can reference it
IF NOT EXISTS (SELECT name FROM sys.indexes WHERE name = N'nc2' and object_id = object_id(N'[dbo].[sysjobsteps]') )
BEGIN
EXECUTE (N'CREATE UNIQUE NONCLUSTERED INDEX nc2 ON sysjobsteps(step_uid)')
END
go
--alter sysdownloadlist table
PRINT ''
PRINT 'Alter table sysdownloadlist...'
ALTER TABLE sysdownloadlist ALTER COLUMN source_server sysname
ALTER TABLE sysdownloadlist ALTER COLUMN target_server sysname
go
--alter sysjobhistory table
PRINT ''
PRINT 'Alter table sysjobhistory...'
ALTER TABLE sysjobhistory ALTER COLUMN server sysname
go
IF EXISTS (SELECT * FROM msdb.dbo.sysobjects WHERE name = N'sysjobhistory' and type = 'U')
BEGIN
UPDATE msdb.dbo.sysjobhistory
SET server = CONVERT(sysname, SERVERPROPERTY('servername'))
WHERE UPPER(server) = '(LOCAL)'
END
go
--alter systargetservers table
PRINT ''
PRINT 'Alter table systargetservers...'
ALTER TABLE systargetservers ALTER COLUMN server_name sysname
go
--alter sysjobsteps table
PRINT ''
PRINT 'Alter table sysjobsteps...'
ALTER TABLE sysjobsteps ALTER COLUMN additional_parameters NVARCHAR(max)
go
--drop syssubsystems table if it exists( to support update from IDW(n) to RTM)
--it will recreated later with the updated schema
IF (OBJECT_ID('dbo.syssubsystems', 'U') IS NOT NULL)
BEGIN
DROP TABLE dbo.syssubsystems
END
--drop column logshipping from sysdbmaintplans table
--alter only if command column is not already nvarchar(max)
IF (EXISTS (SELECT c.* FROM msdb.sys.all_columns c JOIN msdb.sys.all_objects t
ON c.object_id = t.object_id
WHERE (c.name = 'logshipping') AND t.name = 'sysdbmaintplans' AND t.type = 'U'))
BEGIN
ALTER TABLE sysdbmaintplans DROP COLUMN logshipping
END
go
--make sure
--it will recreated later with the updated schema
IF (OBJECT_ID('dbo.sysjobstepslogs', 'U') IS NOT NULL)
BEGIN
ALTER TABLE dbo.sysjobstepslogs ALTER COLUMN log_size bigint
END
-- sysproxylogin upgrade
-- sysproxylogin upgrade
BEGIN TRY
IF EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='principal_id' and id =
(SELECT OBJECT_ID(N'dbo.sysproxylogin', 'U')))
BEGIN
-- convert data from principal_id to sid
exec sp_executesql N'
DECLARE @sid varbinary(85)
DECLARE @principal_id int
DECLARE principal_sid_cursor CURSOR LOCAL
FOR
SELECT distinct principal_id
FROM dbo.sysproxylogin WHERE (sid IS NULL) AND (flags = 2)
OPEN principal_sid_cursor
FETCH NEXT FROM principal_sid_cursor INTO @principal_id
WHILE (@@fetch_status = 0)
BEGIN
SELECT @sid=sid FROM msdb.sys.database_principals WHERE principal_id=@principal_id
IF @sid IS NOT NULL -- principal_id is valid
BEGIN
UPDATE dbo.sysproxylogin
SET sid = @sid
WHERE principal_id = @principal_id
END
ELSE
BEGIN
DELETE FROM dbo.sysproxylogin
WHERE principal_id = @principal_id
END
FETCH NEXT FROM principal_sid_cursor INTO @principal_id
END
CLOSE principal_sid_cursor
DEALLOCATE principal_sid_cursor
'
-- remove obsolete column
DROP INDEX sysproxylogin.clust
ALTER TABLE dbo.sysproxylogin DROP COLUMN principal_id
CREATE UNIQUE CLUSTERED INDEX clust ON sysproxylogin(proxy_id, sid, flags)
END
END TRY
BEGIN CATCH
print 'There was a problem upgrading sysproxylogin table.'
print 'Unable to map existing principal_id values to sid column'
print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
END CATCH
GO
/**************************************************************/
/* Mark system objects */
/**************************************************************/
declare @start datetime
,@name sysname
select @start = start from #InstMsdb
declare newsysobjs cursor for select name from sys.objects where schema_id = 1 and create_date >= @start
open newsysobjs
fetch next from newsysobjs into @name
while @@fetch_status = 0
begin
Exec sp_MS_marksystemobject @name
fetch next from newsysobjs into @name
end
deallocate newsysobjs
drop table #InstMsdb
go
EXECUTE master.dbo.sp_configure N'allow updates', 0
go
RECONFIGURE WITH OVERRIDE
go
PRINT ''
PRINT '-----------------------------------------'
PRINT 'Execution of PRE_SQLAGENT100.SQL complete'
PRINT '-----------------------------------------'
go
/**************************************************************/
/* DMF Pre-upgrade steps */
/**************************************************************/
PRINT 'DMF pre-upgrade steps...'
--
-- >>> CTP5 -> CTP6 Upgrade
--
-- The check is based on presense of ObjectSet tables
-- We also check if principal DMF objects is there
-- if it's not we either upgrade from Yukon
-- or there is nothing to upgrade anyway
IF (OBJECT_ID('[dbo].[syspolicy_policies_internal]', 'U') IS NOT NULL)
AND (OBJECT_ID('[dbo].[syspolicy_object_sets_internal]', 'U') IS NULL)
BEGIN
BEGIN TRY
-- Open transaction - we don't want to delete tables if we don't have a copy of data
BEGIN TRANSACTION
-- Create upgrade marker
CREATE TABLE dbo.dmf_upgrade (id int)
-- STORE DATA
SELECT * INTO msdb.dbo.tmp_syspolicy_target_sets_internal FROM syspolicy_target_sets_internal
SELECT * INTO msdb.dbo.tmp_syspolicy_target_set_levels_internal FROM syspolicy_target_set_levels_internal
SELECT * INTO msdb.dbo.tmp_syspolicy_policies_internal FROM syspolicy_policies_internal
SELECT * INTO msdb.dbo.tmp_syspolicy_system_health_state_internal FROM syspolicy_system_health_state_internal
SELECT * INTO msdb.dbo.tmp_syspolicy_policy_execution_history_internal FROM syspolicy_policy_execution_history_internal
SELECT * INTO msdb.dbo.tmp_syspolicy_policy_execution_history_details_internal FROM syspolicy_policy_execution_history_details_internal
-- Delete policies to invoke the trigger that removes dependent objects (jobs, if any).
DELETE [dbo].[syspolicy_policies_internal]
-- T-SQL Policy jobs are now gone, we must nullify job_id to not violate the foreign key constraint
UPDATE msdb.dbo.tmp_syspolicy_policies_internal SET job_id = NULL
-- DROP TABLES (WITH DEPENDENCIES)
IF (OBJECT_ID('[dbo].[syspolicy_target_set_levels_internal]', 'U') IS NOT NULL) DROP TABLE [dbo].[syspolicy_target_set_levels_internal]
IF (OBJECT_ID('[dbo].[syspolicy_target_sets_internal]', 'U') IS NOT NULL) DROP TABLE [dbo].[syspolicy_target_sets_internal]
IF (OBJECT_ID('[dbo].[syspolicy_policy_execution_history_details_internal]', 'U') IS NOT NULL) DROP TABLE [dbo].[syspolicy_policy_execution_history_details_internal]
IF (OBJECT_ID('[dbo].[syspolicy_policy_execution_history_internal]', 'U') IS NOT NULL) DROP TABLE [dbo].[syspolicy_policy_execution_history_internal]
IF (OBJECT_ID('[dbo].[syspolicy_system_health_state_internal]', 'U') IS NOT NULL) DROP TABLE [dbo].[syspolicy_system_health_state_internal]
IF (OBJECT_ID('[dbo].[syspolicy_policies]', 'V') IS NOT NULL) DROP VIEW [dbo].[syspolicy_policies]
IF (OBJECT_ID('[dbo].[syspolicy_policies_internal]', 'U') IS NOT NULL) DROP TABLE [dbo].[syspolicy_policies_internal]
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF (XACT_STATE() <> 0)
BEGIN
ROLLBACK TRANSACTION;
END
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
PRINT 'ERROR: DMF CTP5 to CTP6 upgrade tasks failed'
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
END CATCH;
END
GO
--
-- <<< CTP5 - CTP6 Upgrade
--
--
-- >>> CTP6 - RTM Upgrade
--
IF (OBJECT_ID('[dbo].[syspolicy_policies_internal]', 'U') IS NOT NULL)
BEGIN
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policies_internal]') AND name='object_set_id' AND is_nullable=0)
BEGIN
ALTER TABLE [dbo].[syspolicy_policies_internal] ALTER COLUMN object_set_id int NULL
END
END
GO
IF (OBJECT_ID('[dbo].[syspolicy_system_health_state_internal]', 'U') IS NOT NULL)
BEGIN
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_system_health_state_internal]') AND name='target_query_expression_with_id' AND is_nullable=1)
BEGIN
IF EXISTS (SELECT * FROM sys.indexes WHERE name = N'IX_syspolicy_system_health_state_internal_target_query_expression_with_id')
DROP INDEX IX_syspolicy_system_health_state_internal_target_query_expression_with_id ON [dbo].[syspolicy_system_health_state_internal]
ALTER TABLE [dbo].[syspolicy_system_health_state_internal] ALTER COLUMN target_query_expression_with_id nvarchar(400) NOT NULL
CREATE INDEX IX_syspolicy_system_health_state_internal_target_query_expression_with_id ON
[dbo].[syspolicy_system_health_state_internal](target_query_expression_with_id)
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_system_health_state_internal]') AND name='target_query_expression' AND is_nullable=1)
BEGIN
ALTER TABLE [dbo].[syspolicy_system_health_state_internal] ALTER COLUMN target_query_expression nvarchar(max) NOT NULL
END
END
GO
IF (OBJECT_ID('[dbo].[syspolicy_policy_execution_history_internal]', 'U') IS NOT NULL)
BEGIN
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_internal]') AND name='policy_id' AND is_nullable=1)
BEGIN
IF EXISTS (SELECT * FROM sys.indexes WHERE name = N'IX_syspolicy_policy_execution_history_internal_end_date_policy_id')
DROP INDEX IX_syspolicy_policy_execution_history_internal_end_date_policy_id ON [dbo].[syspolicy_policy_execution_history_internal]
IF EXISTS (SELECT * FROM sys.indexes WHERE name = N'IX_syspolicy_policy_execution_history_internal_policy_id')
DROP INDEX IX_syspolicy_policy_execution_history_internal_policy_id ON [dbo].[syspolicy_policy_execution_history_internal]
DECLARE @fk_name sysname
SELECT @fk_name = k.name from sys.foreign_keys k
join sys.foreign_key_columns kc on k.object_id = kc.constraint_object_id
join sys.columns c on k.parent_object_id = c.object_id AND kc.parent_column_id = c.column_id
where k.parent_object_id=OBJECT_ID('syspolicy_policy_execution_history_internal')
and c.name = 'policy_id'
IF @fk_name IS NOT NULL
BEGIN
DECLARE @drop_cmd nvarchar(512)
SELECT @drop_cmd = 'ALTER TABLE [dbo].[syspolicy_policy_execution_history_internal] DROP CONSTRAINT ' + QUOTENAME(@fk_name)
EXECUTE (@drop_cmd)
END
END
END
GO
IF (OBJECT_ID('[dbo].[syspolicy_policy_execution_history_internal]', 'U') IS NOT NULL)
BEGIN
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_internal]') AND name='policy_id' AND is_nullable=1)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_internal] ALTER COLUMN policy_id int NOT NULL
CREATE INDEX IX_syspolicy_policy_execution_history_internal_end_date_policy_id
ON [dbo].[syspolicy_policy_execution_history_internal](policy_id, end_date);
CREATE INDEX IX_syspolicy_policy_execution_history_internal_policy_id
ON [dbo].[syspolicy_policy_execution_history_internal](policy_id);
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_internal]') AND name='start_date' AND is_nullable=1)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_internal] ALTER COLUMN [start_date] datetime NOT NULL
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_internal]') AND name='result' AND is_nullable=1)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_internal] ALTER COLUMN result bit NOT NULL
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_internal]') AND name='is_full_run' AND is_nullable=1)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_internal] ALTER COLUMN is_full_run bit NOT NULL
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_internal]') AND name='exception_message' AND is_nullable=0)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_internal] ALTER COLUMN exception_message nvarchar(max) NULL
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_internal]') AND name='exception' AND is_nullable=0)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_internal] ALTER COLUMN exception nvarchar(max) NULL
END
END
GO
IF (OBJECT_ID('[dbo].[syspolicy_policy_execution_history_internal]', 'U') IS NOT NULL)
BEGIN
IF NOT EXISTS (SELECT * from sys.foreign_keys k
join sys.foreign_key_columns kc on k.object_id = kc.constraint_object_id
join sys.columns c on k.parent_object_id = c.object_id AND kc.parent_column_id = c.column_id
where k.parent_object_id=OBJECT_ID('syspolicy_policy_execution_history_internal')
and c.name = 'policy_id')
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_internal] ADD FOREIGN KEY (policy_id) REFERENCES [syspolicy_policies_internal]
END
END
GO
IF (OBJECT_ID('[dbo].[syspolicy_policy_execution_history_details_internal]', 'U') IS NOT NULL)
BEGIN
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_details_internal]') AND name='history_id' AND is_nullable=1)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_details_internal] ALTER COLUMN history_id bigint NOT NULL
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_details_internal]') AND name='target_query_expression_with_id' AND is_nullable=1)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_details_internal] ALTER COLUMN target_query_expression_with_id nvarchar(4000) NOT NULL
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_details_internal]') AND name='target_query_expression' AND is_nullable=1)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_details_internal] ALTER COLUMN target_query_expression nvarchar(4000) NOT NULL
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_details_internal]') AND name='execution_date' AND is_nullable=1)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_details_internal] ALTER COLUMN execution_date datetime NOT NULL
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_details_internal]') AND name='result' AND is_nullable=1)
BEGIN
IF EXISTS (SELECT * FROM sys.indexes WHERE name = N'IX_syspolicy_policy_execution_history_details_internal_result')
DROP INDEX IX_syspolicy_policy_execution_history_details_internal_result ON [dbo].[syspolicy_policy_execution_history_details_internal]
ALTER TABLE [dbo].[syspolicy_policy_execution_history_details_internal] ALTER COLUMN result bit NOT NULL
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_details_internal]') AND name='result_detail' AND is_nullable=0)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_details_internal] ALTER COLUMN result_detail nvarchar(max) NULL
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_details_internal]') AND name='exception_message' AND is_nullable=0)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_details_internal] ALTER COLUMN exception_message nvarchar(max) NULL
END
IF EXISTS (SELECT * FROM sys.columns WHERE object_id=OBJECT_ID('[dbo].[syspolicy_policy_execution_history_details_internal]') AND name='exception' AND is_nullable=0)
BEGIN
ALTER TABLE [dbo].[syspolicy_policy_execution_history_details_internal] ALTER COLUMN exception nvarchar(max) NULL
END
END
GO
--
-- <<< CTP6 - RTM Upgrade
--
--
-- >>> Katmai RTM - KJ CTP2 Upgrade
--
-- If there is no 'is_system' column in the following tables, add it
--
-- Need to take care of Shiloh/Yukon upgrade - no DMF objects exist
-- Only check for policies, assuming we either have all DMF tables or none
-- If installation is corrupted (there is policies table, but no conditions table) upgrade fails
--
IF (OBJECT_ID('[dbo].[syspolicy_policies_internal]', 'U') IS NOT NULL)
BEGIN
IF NOT EXISTS (SELECT * FROM sys.columns WHERE name = 'is_system' AND object_id = OBJECT_ID('[dbo].[syspolicy_policies_internal]', 'U'))
ALTER TABLE syspolicy_policies_internal ADD is_system bit NOT NULL DEFAULT (0)
IF NOT EXISTS (SELECT * FROM sys.columns WHERE name = 'is_system' AND object_id = OBJECT_ID('[dbo].[syspolicy_conditions_internal]', 'U'))
ALTER TABLE syspolicy_conditions_internal ADD is_system bit NOT NULL DEFAULT (0)
IF NOT EXISTS (SELECT * FROM sys.columns WHERE name = 'is_system' AND object_id = OBJECT_ID('[dbo].[syspolicy_object_sets_internal]', 'U'))
ALTER TABLE syspolicy_object_sets_internal ADD is_system bit NOT NULL DEFAULT (0)
END
GO
-- Fix indexes on syspolicy_policy_execution_history_details_internal
--
IF (OBJECT_ID('[dbo].[syspolicy_policies_internal]', 'U') IS NOT NULL)
BEGIN
IF EXISTS (SELECT * FROM sys.indexes WHERE name = N'IX_syspolicy_policy_execution_history_details_internal_result')
DROP INDEX IX_syspolicy_policy_execution_history_details_internal_result ON [dbo].[syspolicy_policy_execution_history_details_internal]
IF NOT EXISTS (SELECT * FROM sys.key_constraints WHERE name = N'PK_syspolicy_policy_execution_history_details_id')
BEGIN
DECLARE @ix_name sysname
SELECT @ix_name = name FROM sys.key_constraints
WHERE parent_object_id = OBJECT_ID('[dbo].[syspolicy_policy_execution_history_details_internal]', 'U') AND type = 'PK' AND is_system_named = 1
IF @ix_name IS NOT NULL
BEGIN
DECLARE @drop_cmd nvarchar(512)
SELECT @drop_cmd = 'ALTER TABLE [dbo].[syspolicy_policy_execution_history_details_internal] DROP CONSTRAINT ' + QUOTENAME(@ix_name)
EXECUTE (@drop_cmd)
END
ALTER TABLE [dbo].[syspolicy_policy_execution_history_details_internal]
ADD CONSTRAINT [PK_syspolicy_policy_execution_history_details_id] PRIMARY KEY CLUSTERED(history_id, detail_id)
END
END
GO
--
-- <<< Katmai RTM - KJ CTP2 Upgrade
--
/**************************************************************/
/* End of DMF Pre-upgrade steps */
/**************************************************************/
/**********************************************************************/
/* DC Pre-upgrade steps */
/**********************************************************************/
GO
PRINT 'DC pre-upgrade steps...';
-- Capture current state of DataCollector in temp table
-- and re-enable collector after script upgrade
-- #304027 - Data Collection is disabled when upgrading SQL Server 2008
-- service pack upgrade or hotfix upgrade
PRINT 'Check if Data collector config table exists...'
IF (OBJECT_ID(N'[dbo].[syscollector_config_store_internal]', 'U') IS NOT NULL)
BEGIN
IF (OBJECT_ID('tempdb..#data_collector_status', 'U') IS NOT NULL)
BEGIN
PRINT 'Dropping existing temp table tempdb..#data_collector_status...'
DROP TABLE #data_collector_status
END
DECLARE @collector_enabled int;
SELECT @collector_enabled = ISNULL(CONVERT(int, parameter_value),0)
FROM [dbo].[syscollector_config_store_internal]
WHERE parameter_name = 'CollectorEnabled'
PRINT 'Data Collector state before upgrade: ' + CONVERT(varchar, @collector_enabled)
SELECT @collector_enabled AS data_collector_old_status
INTO #data_collector_status
END
-- Capture Collection set status before upgrade
PRINT 'pre_dc100::Check if syscollector_collection_sets_internal table exists...'
IF (OBJECT_ID(N'[dbo].[syscollector_collection_sets_internal]', 'U') IS NOT NULL)
BEGIN
-- Capture Collection set status in temp table
IF (OBJECT_ID('tempdb..#data_collector_collectionset_status', 'U') IS NOT NULL)
BEGIN
PRINT 'pre_dc100::Dropping existing temp table tempdb..#data_collector_collectionset_status...'
DROP TABLE #data_collector_collectionset_status
END
PRINT 'pre_dc100::Capturing Collection set status in temp table...'
SELECT collection_set_uid, name, is_running
INTO #data_collector_collectionset_status
FROM [dbo].[syscollector_collection_sets_internal]
END
GO
--
-- CTP6->CTP6 Refresh
--
-- Drop the parent_log_id->log_id self reference
IF ((OBJECT_ID ('dbo.syscollector_execution_log_internal') IS NOT NULL)
AND (OBJECT_ID('dbo.FK_syscollector_execution_log_parent_log_id', 'F') IS NOT NULL))
BEGIN
PRINT 'Dropping [FK_syscollector_execution_log_parent_log_id]';
ALTER TABLE [dbo].[syscollector_execution_log_internal] DROP CONSTRAINT [FK_syscollector_execution_log_parent_log_id];
END
--
-- >>> CTP5 -> CTP6 Upgrade
--
-- Change int log_id columns to bigint
IF (OBJECT_ID ('dbo.syscollector_execution_log_internal') IS NOT NULL) AND EXISTS (
SELECT *
FROM sys.columns AS c
INNER JOIN sys.types AS t ON c.system_type_id = t.system_type_id
WHERE [object_id] = OBJECT_ID ('dbo.syscollector_execution_log_internal')
AND c.name = 'log_id' AND t.name = 'int'
)
BEGIN
BEGIN TRY
PRINT 'Starting log_id int -> bigint conversion'
BEGIN TRANSACTION PreInstMsdb100_DCUpgrade
-- Drop PK/FK constaints referencing log_id columns so we can change the data types of these columns
PRINT 'Dropping [FK_syscollector_execution_stats_log_id]';
ALTER TABLE [dbo].[syscollector_execution_stats_internal] DROP CONSTRAINT [FK_syscollector_execution_stats_log_id];
PRINT 'Dropping [PK_syscollector_execution_stats]';
ALTER TABLE [dbo].[syscollector_execution_stats_internal] DROP CONSTRAINT [PK_syscollector_execution_stats];
PRINT 'Dropping [PK_syscollector_execution_log]';
ALTER TABLE [dbo].[syscollector_execution_log_internal] DROP CONSTRAINT [PK_syscollector_execution_log];
-- Truncate the DC log table to avoid causing unnecessary delays during CTP upgrade
PRINT 'Truncating [syscollector_execution_log_internal]...';
TRUNCATE TABLE [dbo].[syscollector_execution_log_internal];
-- log_id values stored in syscollector_execution_stats will no longer be valid after we have truncated the log table
PRINT 'Truncating [syscollector_execution_stats_internal]...';
TRUNCATE TABLE [dbo].[syscollector_execution_stats_internal];
-- Change the data type of all log_id columns
PRINT 'Changing log_id column datatypes...';
PRINT ' syscollector_execution_stats_internal.log_id';
ALTER TABLE [dbo].[syscollector_execution_stats_internal] ALTER COLUMN [log_id] bigint NOT NULL;
PRINT ' syscollector_execution_log_internal.log_id';
ALTER TABLE [dbo].[syscollector_execution_log_internal] ALTER COLUMN [log_id] bigint NOT NULL;
PRINT ' syscollector_execution_log_internal.parent_log_id';
ALTER TABLE [dbo].[syscollector_execution_log_internal] ALTER COLUMN [parent_log_id] bigint NULL;
END TRY
BEGIN CATCH
IF (XACT_STATE() <> 0)
BEGIN
ROLLBACK TRANSACTION;
END
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
PRINT 'ERROR: DC CTP5 to CTP6 upgrade tasks failed'
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
END CATCH;
END
GO
-- Re-create the PK/FK constraints that we dropped in order to modify column datatypes
IF (OBJECT_ID ('dbo.syscollector_execution_log_internal') IS NOT NULL) AND NOT EXISTS (SELECT * FROM sys.objects WHERE name = 'PK_syscollector_execution_log' AND [schema_id] = SCHEMA_ID ('dbo'))
BEGIN
BEGIN TRY
PRINT 'Creating PK_syscollector_execution_log...';
ALTER TABLE [dbo].[syscollector_execution_log_internal] ADD CONSTRAINT [PK_syscollector_execution_log]
PRIMARY KEY CLUSTERED (log_id ASC);
END TRY
BEGIN CATCH
-- If we're still in the transaction started by the prior batch, roll it back so that it's
-- as if we never dropped any constraints
PRINT 'ERROR: DC CTP5 to CTP6 upgrade tasks failed to create [PK_syscollector_execution_log] '
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
END CATCH;
END
GO
IF (OBJECT_ID ('dbo.syscollector_execution_stats_internal') IS NOT NULL) AND NOT EXISTS (SELECT * FROM sys.objects WHERE name = 'PK_syscollector_execution_stats' AND [schema_id] = SCHEMA_ID ('dbo'))
BEGIN
BEGIN TRY
PRINT 'Creating PK_syscollector_execution_stats...';
ALTER TABLE [dbo].[syscollector_execution_stats_internal] ADD CONSTRAINT [PK_syscollector_execution_stats]
PRIMARY KEY CLUSTERED (log_id ASC, task_name ASC, log_time DESC);
END TRY
BEGIN CATCH
PRINT 'ERROR: DC CTP5 to CTP6 upgrade tasks failed to create [PK_syscollector_execution_stats] '
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
END CATCH;
END
GO
IF (OBJECT_ID ('dbo.syscollector_execution_stats_internal') IS NOT NULL) AND NOT EXISTS (SELECT * FROM sys.objects WHERE name = 'FK_syscollector_execution_stats_log_id' AND [schema_id] = SCHEMA_ID ('dbo'))
BEGIN
BEGIN TRY
PRINT 'Creating FK_syscollector_execution_stats_log_id...';
ALTER TABLE [dbo].[syscollector_execution_stats_internal] ADD CONSTRAINT [FK_syscollector_execution_stats_log_id]
FOREIGN KEY (log_id) REFERENCES [dbo].[syscollector_execution_log_internal] (log_id)
ON DELETE CASCADE;
END TRY
BEGIN CATCH
PRINT 'ERROR: DC CTP5 to CTP6 upgrade tasks failed to create [FK_syscollector_execution_stats_log_id] '
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
END CATCH;
END
GO
IF (@@TRANCOUNT > 0) COMMIT TRANSACTION;
GO
IF (OBJECT_ID ('dbo.syscollector_execution_log_internal') IS NOT NULL)
BEGIN
EXEC sp_refreshview 'dbo.syscollector_execution_log'
EXEC sp_refreshview 'dbo.syscollector_execution_stats'
END
GO
--
-- <<< CTP5 - CTP6 Upgrade
--
--
-- >>> Delete auto-generated T-SQL packages stored in msdb.
--
IF OBJECT_ID ('dbo.syscollector_tsql_query_collector') IS NOT NULL
BEGIN
RAISERROR ('Deleting cached auto-generated T-SQL Data Collection packages from msdb...', 0, 1) WITH NOWAIT
/*
** We have a row in [syscollector_tsql_query_collector] for each T-SQL collection item, and
** each item has a collection and an upload package. There's a DELETE trigger on this table
** that will take care of deleting the packages from sysssispackages for us. The packages
** will be re-generated automatically the next time their parent collection set's collection
** package runs.
*/
DELETE FROM syscollector_tsql_query_collector
END
--
-- <<< Delete auto-generated T-SQL packages stored in msdb.
--
GO
PRINT 'End of DC pre-upgrade steps.';
/**********************************************************************/
/* End of DC Pre-upgrade steps */
/**********************************************************************/
GO
/**********************************************************************/
/* DAC Pre-upgrade steps */
/**********************************************************************/
PRINT 'DAC pre-upgrade steps...';
GO
RAISERROR('Starting DAC pre-upgrade steps ...', 0, 1) WITH NOWAIT;
--
-- SQL Server 2008 R2 : CTP2->CTP3 upgrade
-- 1. sysdac_history table has two extra columns that we added in CTP3 (required, comments).
-- It has been decided not to preserve CTP2 history data i.e. on an upgrade from CTP2->CTP3, deploy/uninstall logs are cleared.
--
-- 2. {sysdac_packages_internal, sysdac_packages, sysdac_parts_internal, sysdac_parts} are deleted. They are replaced with new artifacts in CTP3.
--
IF (OBJECT_ID('[dbo].[sysdac_history_internal]', 'U') IS NOT NULL)
BEGIN
IF NOT EXISTS(SELECT 1
FROM sys.columns
WHERE (name = 'comments' OR name = 'required') AND
object_id = OBJECT_ID('[dbo].[sysdac_history_internal]', 'U')
)
BEGIN
DROP TABLE [dbo].[sysdac_history_internal]
END
END
IF (OBJECT_ID('[dbo].[sysdac_parts]', 'V') IS NOT NULL)
DROP VIEW [dbo].[sysdac_parts]
IF (OBJECT_ID('[dbo].[sysdac_packages]', 'V') IS NOT NULL)
DROP VIEW [dbo].[sysdac_packages]
IF (OBJECT_ID('[dbo].[sysdac_parts_internal]', 'U') IS NOT NULL)
DROP TABLE [dbo].[sysdac_parts_internal]
IF (OBJECT_ID('[dbo].[sysdac_packages_internal]', 'U') IS NOT NULL)
DROP TABLE [dbo].[sysdac_packages_internal]
PRINT 'End of DAC pre-upgrade steps.';
GO
/**********************************************************************/
/* End of DAC Pre-upgrade steps */
/**********************************************************************/
-------------------------------------------------------------------------
--
/**************************************************************/
/* Utility pre-upgrade steps */
/**************************************************************/
/**************************************************************/
/* End of Utility pre-upgrade steps */
/**************************************************************/
/**********************************************************************/
/* MSDB.SQL */
/* */
/* Creates the MSDB database and some utility SPs. */
/* */
/* */
/* Copyright (c) Microsoft Corporation */
/* All Rights Reserved. */
/* */
/**********************************************************************/
PRINT '----------------------------------'
PRINT 'Starting execution of MSDB.SQL'
PRINT '----------------------------------'
go
--this version of instmsdb should be executed only against 11.0 and later servers
IF (@@microsoftversion / 0x01000000) < 11
BEGIN
RAISERROR('This version of instmsdb.sql should only be executed against 11.0 and later servers.', 20, 127) WITH LOG
END
go
-- disable the event collection for policies while running this script
IF EXISTS (SELECT * FROM sys.server_triggers WHERE name = N'syspolicy_server_trigger')
DISABLE TRIGGER [syspolicy_server_trigger] ON ALL SERVER
GO
IF EXISTS (SELECT * FROM sys.service_queues where name = N'syspolicy_event_queue')
ALTER QUEUE [syspolicy_event_queue] WITH ACTIVATION (STATUS = OFF)
GO
/*********************************************************************/
/* Create auxilary procedure to enable OBD (Off By Default component */
/*********************************************************************/
CREATE PROCEDURE #sp_enable_component
@comp_name sysname,
@advopt_old_value INT OUT,
@comp_old_value INT OUT
AS
BEGIN
SELECT @advopt_old_value=cast(value_in_use as int) from sys.configurations where name = 'show advanced options';
SELECT @comp_old_value=cast(value_in_use as int) from sys.configurations where name = @comp_name;
EXEC sp_configure 'show advanced options',1;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure @comp_name, 1;
RECONFIGURE WITH OVERRIDE;
END
go
CREATE PROCEDURE #sp_restore_component_state
@comp_name sysname,
@advopt_old_value INT,
@comp_old_value INT
AS
BEGIN
EXEC sp_configure @comp_name, @comp_old_value;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'show advanced options',@advopt_old_value;
RECONFIGURE WITH OVERRIDE;
END
go
-- Explicitly set the options that the server stores with the object in sysobjects.status
-- so that it doesn't matter if the script is run using a DBLib or ODBC based client.
SET QUOTED_IDENTIFIER OFF -- We don't use quoted identifiers
SET ANSI_NULLS ON -- We don't want (NULL = NULL) == TRUE
go
SET ANSI_PADDING ON -- Set so that trailing zeros aren't trimmed off sysjobs.owner_login_sid
go
-- Allow updates to system catalogs so that all our SP's inherit full DML capability on
-- system objects and so that we can exercise full DDL control on our system objects
EXECUTE master.dbo.sp_configure N'allow updates', 1
go
RECONFIGURE WITH OVERRIDE
go
/**************************************************************/
/* */
/* D A T A B A S E C R E A T I O N */
/* */
/**************************************************************/
IF (NOT EXISTS (SELECT name
FROM master.dbo.sysdatabases
WHERE (name = N'msdb')))
BEGIN
PRINT 'Creating the msdb database...'
END
go
USE master
go
SET NOCOUNT ON
-- NOTE: It is important that this script can be re-run WITHOUT causing loss of data, hence
-- we only create the database if it missing (if the database already exists we test
-- that it has enough free space and if not we expand both the device and the database).
DECLARE @model_db_size INT
DECLARE @msdb_db_size INT
DECLARE @sz_msdb_db_size VARCHAR(10)
DECLARE @device_directory NVARCHAR(520)
DECLARE @page_size INT
DECLARE @size INT
DECLARE @free_db_space FLOAT
SELECT @page_size = 8
IF (NOT EXISTS (SELECT name
FROM master.dbo.sysdatabases
WHERE (name = N'msdb')))
BEGIN
-- Make sure that we create [the data portion of] MSDB to be at least as large as
-- the MODEL database
SELECT @model_db_size = (SUM(size) * @page_size)
FROM model.dbo.sysfiles
IF (@model_db_size > 3072) -- 3 is the minimum required size for MSDB (in megabytes)
SELECT @msdb_db_size = @model_db_size
ELSE
SELECT @msdb_db_size = 3072
SELECT @device_directory = SUBSTRING(filename, 1, CHARINDEX(N'master.mdf', LOWER(filename)) - 1)
FROM master.dbo.sysaltfiles
WHERE (name = N'master')
-- Drop any existing MSDBData / MSDBLog file(s)
DECLARE @advopt_old_value INT
DECLARE @comp_old_value INT
EXECUTE #sp_enable_component 'xp_cmdshell', @advopt_old_value out, @comp_old_value out
EXECUTE(N'EXECUTE master.dbo.xp_cmdshell N''DEL ' + @device_directory + N'MSDBData.mdf'', no_output')
EXECUTE(N'EXECUTE master.dbo.xp_cmdshell N''DEL ' + @device_directory + N'MSDBLog.ldf'', no_output')
EXECUTE #sp_restore_component_state 'xp_cmdshell', @advopt_old_value, @comp_old_value
-- Create the database
PRINT ''
PRINT 'Creating MSDB database...'
SELECT @sz_msdb_db_size = RTRIM(LTRIM(CONVERT(VARCHAR, @msdb_db_size)))
EXECUTE (N'CREATE DATABASE msdb ON (NAME = N''MSDBData'', FILENAME = N''' + @device_directory + N'MSDBData.mdf'', SIZE = ' + @sz_msdb_db_size + N'KB, MAXSIZE = UNLIMITED, FILEGROWTH = 10%)
LOG ON (NAME = N''MSDBLog'', FILENAME = N''' + @device_directory + N'MSDBLog.ldf'', SIZE = 512KB, MAXSIZE = UNLIMITED, FILEGROWTH = 10%)')
EXECUTE (N'ALTER DATABASE msdb SET DB_CHAINING ON')
PRINT ''
END
ELSE
BEGIN
PRINT 'Checking the size of MSDB...'
DBCC UPDATEUSAGE(N'msdb') WITH NO_INFOMSGS
-- Make sure that MSDBLog has unlimited growth
ALTER DATABASE msdb MODIFY FILE (NAME = N'MSDBLog', MAXSIZE = 2TB)
-- Determine amount of free space in msdb. We need at least 2MB free.
SELECT @free_db_space = ((((SELECT SUM(size)
FROM msdb.dbo.sysfiles
WHERE status & 0x8040 = 0) -
(SELECT SUM(reserved)
FROM msdb.dbo.sysindexes
WHERE indid IN (0, 1, 255))) * @page_size) / 1024.0)
IF (@free_db_space < 2)
BEGIN
DECLARE @logical_file_name sysname
DECLARE @os_file_name NVARCHAR(255)
DECLARE @size_as_char VARCHAR(10)
SELECT @logical_file_name = name,
@os_file_name = filename,
@size_as_char = CONVERT(VARCHAR(10), size*8 + 2048) -- size column in sysaltfiles is in number of 8KB pages
FROM master.dbo.sysaltfiles
WHERE (name = N'MSDBData')
set @os_file_name = QUOTENAME(@os_file_name,'''')
PRINT 'Attempting to expand the msdb database...'
EXECUTE(N'ALTER DATABASE msdb MODIFY FILE (NAME = N''' + @logical_file_name + N''',
FILENAME = N' + @os_file_name + N',
SIZE =' + @size_as_char + N'KB)')
IF (@@error <> 0)
RAISERROR('Unable to expand the msdb database. MSDB.SQL terminating.', 20, 127) WITH LOG
END
PRINT ''
END
EXECUTE (N'ALTER DATABASE msdb SET TRUSTWORTHY ON')
go
-- truncate log on checkpoint
ALTER DATABASE msdb
SET RECOVERY SIMPLE
go
USE msdb
go
-- Check that we're in msdb
IF (DB_NAME() <> N'msdb')
RAISERROR('A problem was encountered accessing msdb. MSDB.SQL terminating.', 20, 127) WITH LOG
go
-- Add the guest user
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysusers
WHERE (name = N'guest')
AND (hasdbaccess = 1)))
BEGIN
PRINT ''
EXECUTE sys.sp_adduser N'guest'
END
go
CHECKPOINT
go
/**************************************************************/
/* Record time of start of creates */
/**************************************************************/
SELECT start = getdate() INTO #InstMsdb
go
/**************************************************************/
/* */
/* T A B L E D R O P S */
/* */
/**************************************************************/
SET NOCOUNT ON
DECLARE @build_number INT
SELECT @build_number = @@microsoftversion & 0xffff
-- Do any necessary changes based on build number here
/**************************************************************/
/* */
/* F I N I S H E D T A B L E D R O P S */
/* */
/**************************************************************/
PRINT '----------------------------------'
PRINT 'Finished execution of MSDB.SQL'
PRINT '----------------------------------'
go
PRINT '-----------------------------------------'
PRINT 'Starting execution of MSDB_VERSIONING.SQL'
PRINT '-----------------------------------------'
go
-- This table is used by SqlScriptUpgrade to detect the Sql11 version (the code is in <>\sql\mpu\sqlagent\scripts\msdb_upgrade_discovery.sql)
-- Even though the version numbers are taken from sql_version.h so they match the server version,
-- the intent here is different. We only use the major version (for now).
IF (OBJECT_ID(N'dbo.msdb_version', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table msdb_version...'
CREATE TABLE dbo.msdb_version
(
id INT IDENTITY,
version_string NVARCHAR(255) NOT NULL,
version_major INT NOT NULL,
version_minor INT NOT NULL,
version_build INT NOT NULL,
version_revision INT NOT NULL
)
END
GO
-- Even if the table exists already, update the version.
TRUNCATE TABLE dbo.msdb_version
GO
DECLARE @vsmaj INT
DECLARE @vsmin INT
DECLARE @vsbld INT
DECLARE @vsrev INT
DECLARE @vsstr NVARCHAR(255)
-- The variables below will be initialized during preprocessing.
-- The right side of the assignment will be replaced with values from sql\version\sqlversion.h
-- Actually MSDB version number defines MSDB own version that is not related to SQL product version.
-- We use the same SQL version from sqlversion.h just for an automatic build process. Thus MSDB
-- version happens being always updated in every build even though there might be no changes in MSDB.
SET @vsmaj = 11;
SET @vsmin = 0;
SET @vsbld = 3000;
SET @vsrev = 0;
SET @vsstr = CAST (@vsmaj AS NVARCHAR(10)) + N'.' +
CAST (@vsmin AS NVARCHAR(10)) + N'.' +
CAST (@vsbld AS NVARCHAR(10)) + N'.' +
CAST (@vsrev AS NVARCHAR(10));
INSERT INTO msdb.dbo.msdb_version (version_string, version_major, version_minor, version_build, version_revision)
VALUES (@vsstr, @vsmaj, @vsmin, @vsbld, @vsrev)
GO
PRINT '-----------------------------------------'
PRINT 'Finished execution of MSDB_VERSIONING.SQL'
PRINT '-----------------------------------------'
GO
---------------------------------------------------------------
-- Replication Datatype mapping tables
---------------------------------------------------------------
-- REVIEW - Is this needed? What does this do?
exec sys.sp_MSrepl_dropdatatypemappings
go
CHECKPOINT
go
---------------------------------------------------------------
-- Replication Datatype mapping tables
---------------------------------------------------------------
exec sys.sp_MSrepl_createdatatypemappings
go
CHECKPOINT
go
/**********************************************************************/
/* SQLAGENT.SQL */
/* */
/* Installs the tables, triggers and stored procedures necessary for */
/* supporting local (and multi-server) jobs, alerts, operators, and */
/* backup history. These objects are used by SQL SMO, SQL Management */
/* Studio and SQLServerAgent */
/* */
/* All Rights Reserved. */
/* */
/**********************************************************************/
/**************************************************************/
/* drop certificate signature from Agent signed sps */
/**************************************************************/
BEGIN TRANSACTION
declare @sp sysname
declare @exec_str nvarchar(1024)
declare ms_crs_sps cursor global for select object_name(crypts.major_id)
from sys.crypt_properties crypts, sys.certificates certs
where crypts.thumbprint = certs.thumbprint
and crypts.class = 1
and certs.name = '##MS_AgentSigningCertificate##'
open ms_crs_sps
fetch next from ms_crs_sps into @sp
while @@fetch_status = 0
begin
if exists(select * from sys.objects where name = @sp)
begin
print 'Dropping signature from: ' + @sp
set @exec_str = N'drop signature from ' + quotename(@sp) + N' by certificate [##MS_AgentSigningCertificate##]'
Execute(@exec_str)
if (@@error <> 0)
begin
declare @err_str nvarchar(1024)
set @err_str = 'Cannot drop signature from ' + quotename(@sp) + '. Terminating.'
close ms_crs_sps
deallocate ms_crs_sps
ROLLBACK TRANSACTION
RAISERROR(@err_str, 20, 127) WITH LOG
return
end
end
fetch next from ms_crs_sps into @sp
end
close ms_crs_sps
deallocate ms_crs_sps
COMMIT TRANSACTION
go
/**************************************************************/
/* */
/* D E F A U L T S */
/* */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'default_sdl_error_message')
AND (type = 'D')))
EXECUTE('CREATE DEFAULT default_sdl_error_message AS NULL')
go
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'default_current_date')
AND (type = 'D')))
EXECUTE('CREATE DEFAULT default_current_date AS GETDATE()')
go
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'default_zero')
AND (type = 'D')))
EXECUTE('CREATE DEFAULT default_zero AS 0')
go
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'default_one')
AND (type = 'D')))
EXECUTE('CREATE DEFAULT default_one AS 1')
go
/**************************************************************/
/* */
/* T A B L E S */
/* */
/**************************************************************/
/**************************************************************/
/* SYSPROXIES */
/**************************************************************/
IF (OBJECT_ID(N'dbo.sysproxies', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table sysproxies...'
CREATE TABLE dbo.sysproxies
(
proxy_id INT IDENTITY, --used to identify a proxy
name sysname NOT NULL, --friendly name of a proxy
credential_id INT NOT NULL,
enabled TINYINT NOT NULL,
description NVARCHAR(512) NULL, --nvarchar(512)
user_sid VARBINARY(85) NOT NULL, --sid of proxy NT user
credential_date_created DATETIME NOT NULL --the date the associated credential has been created
)
CREATE UNIQUE CLUSTERED INDEX clust ON sysproxies(proxy_id)
CREATE UNIQUE NONCLUSTERED INDEX nc1 ON sysproxies(name)
END
go
IF (OBJECT_ID(N'dbo.syssubsystems', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table syssubsystems...'
CREATE TABLE dbo.syssubsystems
(
subsystem_id INT NOT NULL, -- used to identify the subsystem
subsystem NVARCHAR(40) COLLATE database_default NOT NULL, -- Name of subsystem
description_id INT NULL, -- Message number of description string. These messages are stored in sysmessages table for localization purposes. Same story as for Shiloh
subsystem_dll NVARCHAR(255) COLLATE database_default NULL, -- Store full path of the name of subsystem dll subsystem are always installed in the binn folder of an instance
agent_exe NVARCHAR(255) COLLATE database_default NULL, -- Full path to the executable that use the subsystem
start_entry_point NVARCHAR(30) COLLATE database_default NULL, -- Function called when initializing subsystem
event_entry_point NVARCHAR(30) COLLATE database_default NULL, -- Function called when executing a subsystem step
stop_entry_point NVARCHAR(30) COLLATE database_default NULL, -- Function called when unloading a subsystem
max_worker_threads INT NULL -- Number of maximum concurrent steps for a subsystem
)
CREATE UNIQUE CLUSTERED INDEX clust ON syssubsystems(subsystem_id)
CREATE UNIQUE NONCLUSTERED INDEX nc1 ON syssubsystems(subsystem)
END
go
IF (OBJECT_ID(N'dbo.sysproxysubsystem', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table sysproxysubsystem...'
CREATE TABLE dbo.sysproxysubsystem
(
subsystem_id INT NOT NULL, -- used to identify the subsystem
proxy_id INT NOT NULL, -- used to identify the proxy
)
CREATE UNIQUE CLUSTERED INDEX clust ON sysproxysubsystem(subsystem_id, proxy_id)
END
go
IF (OBJECT_ID(N'dbo.sysproxylogin', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table sysproxylogin...'
CREATE TABLE dbo.sysproxylogin
(
proxy_id INT NOT NULL, --used to identify the proxy
sid VARBINARY(85) NULL, --keep logins, fixed server roles or msdb database roles
flags INT DEFAULT 0 NOT NULL -- tells is member_id is login = 0, server fixed role, msdb role.
)
CREATE UNIQUE CLUSTERED INDEX clust ON sysproxylogin(proxy_id, sid, flags)
END
go
PRINT ''
PRINT 'Creating view sysproxyloginsubsystem_view...'
go
IF (NOT OBJECT_ID(N'dbo.sysproxyloginsubsystem_view', 'V') IS NULL)
DROP VIEW sysproxyloginsubsystem_view
go
CREATE VIEW sysproxyloginsubsystem_view
AS
SELECT ps.subsystem_id AS subsystem_id, pl.proxy_id AS proxy_id, pl.sid AS sid, pl.flags AS flags
FROM sysproxylogin pl JOIN sysproxysubsystem ps ON pl.proxy_id = ps.proxy_id
go
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sqlagent_info')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sqlagent_info...'
CREATE TABLE sqlagent_info
(
attribute sysname NOT NULL,
value NVARCHAR(512) NOT NULL
)
END
go
/**************************************************************/
/* SYSDOWNLOADLIST */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysdownloadlist')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysdownloadlist...'
CREATE TABLE sysdownloadlist
(
instance_id INT IDENTITY NOT NULL,
source_server sysname NOT NULL,
operation_code TINYINT NOT NULL,
object_type TINYINT NOT NULL,
object_id UNIQUEIDENTIFIER NOT NULL,
target_server sysname NOT NULL,
error_message NVARCHAR(1024) NULL,
date_posted DATETIME NOT NULL,
date_downloaded DATETIME NULL,
status TINYINT NOT NULL,
deleted_object_name sysname NULL
)
EXECUTE sys.sp_bindefault default_sdl_error_message, N'sysdownloadlist.error_message'
EXECUTE sys.sp_bindefault default_current_date, N'sysdownloadlist.date_posted'
EXECUTE sys.sp_bindefault default_zero, N'sysdownloadlist.status'
CREATE UNIQUE CLUSTERED INDEX clust ON sysdownloadlist(instance_id)
CREATE NONCLUSTERED INDEX nc1 ON sysdownloadlist(target_server)
CREATE NONCLUSTERED INDEX nc2 ON sysdownloadlist(object_id)
END
go
/**************************************************************/
/* SYSJOBHISTORY */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysjobhistory')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysjobhistory...'
CREATE TABLE sysjobhistory
(
instance_id INT IDENTITY NOT NULL,
job_id UNIQUEIDENTIFIER NOT NULL,
step_id INT NOT NULL,
step_name sysname NOT NULL,
sql_message_id INT NOT NULL,
sql_severity INT NOT NULL,
message NVARCHAR(4000) NULL,
run_status INT NOT NULL,
run_date INT NOT NULL,
run_time INT NOT NULL,
run_duration INT NOT NULL,
operator_id_emailed INT NOT NULL,
operator_id_netsent INT NOT NULL,
operator_id_paged INT NOT NULL,
retries_attempted INT NOT NULL,
server sysname NOT NULL
)
CREATE UNIQUE CLUSTERED INDEX clust ON sysjobhistory(instance_id)
CREATE NONCLUSTERED INDEX nc1 ON sysjobhistory(job_id)
END
ELSE
BEGIN
ALTER TABLE sysjobhistory ALTER COLUMN
message NVARCHAR(4000) NULL
END
go
/**************************************************************/
/* sysoriginatingservers */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysoriginatingservers')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysoriginatingservers...'
CREATE TABLE dbo.sysoriginatingservers
(
-- There is only a single MSX server record in this table (originating_server_id = 1)
-- 0 is generated by sysoriginatingservers_view and indicates the local server
originating_server_id INT CONSTRAINT CK_originating_server_id_MustBe_1 CHECK (originating_server_id = 1)
DEFAULT (1) UNIQUE CLUSTERED,
originating_server sysname NOT NULL UNIQUE NONCLUSTERED,
--Mark this record as a MSX server entry
master_server bit CONSTRAINT CK_master_server_MustBe_1 CHECK (master_server = 1)
DEFAULT (1)
)
END
go
/**************************************************************/
/* trig_sysoriginatingservers_delete */
/**************************************************************/
PRINT ''
PRINT 'Creating trigger trig_sysoriginatingservers_delete...'
IF NOT OBJECT_ID('dbo.trig_sysoriginatingservers_delete', 'TR') IS NULL
DROP TRIGGER dbo.trig_sysoriginatingservers_delete
GO
CREATE TRIGGER dbo.trig_sysoriginatingservers_delete
ON dbo.sysoriginatingservers
FOR DELETE
AS
BEGIN
SET NOCOUNT ON
-- Only a single MSX server entry can exist in this table. ie. originating_server_id = 1 and master_server = 1.
IF((EXISTS (SELECT *
FROM deleted AS d
JOIN dbo.sysjobs AS j ON d.originating_server_id = j.originating_server_id)) OR
(EXISTS (SELECT *
FROM deleted AS d
JOIN dbo.sysschedules AS s ON d.originating_server_id = s.originating_server_id)))
BEGIN
RAISERROR(14380, -1, -1)
ROLLBACK TRANSACTION
RETURN
END
END
go
/**************************************************************/
/* sysoriginatingservers_view */
/**************************************************************/
PRINT ''
PRINT 'Creating view sysoriginatingservers_view...'
GO
IF (NOT OBJECT_ID(N'dbo.sysoriginatingservers_view', 'V') IS NULL)
DROP VIEW sysoriginatingservers_view
GO
CREATE VIEW dbo.sysoriginatingservers_view(originating_server_id, originating_server, master_server)
AS
SELECT
0 AS originating_server_id,
UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))) AS originating_server,
0 AS master_server
UNION
SELECT
originating_server_id,
originating_server,
master_server
FROM
dbo.sysoriginatingservers
GO
/**************************************************************/
/* SYSJOBS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysjobs')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysjobs...'
CREATE TABLE sysjobs
(
job_id UNIQUEIDENTIFIER NOT NULL,
originating_server_id INT NOT NULL, -- REFERENCE enforced by trig_sysjobs_insert_update
name sysname NOT NULL,
enabled TINYINT NOT NULL,
description NVARCHAR(512) NULL,
start_step_id INT NOT NULL,
category_id INT NOT NULL,
owner_sid VARBINARY(85) NOT NULL,
notify_level_eventlog INT NOT NULL,
notify_level_email INT NOT NULL,
notify_level_netsend INT NOT NULL,
notify_level_page INT NOT NULL,
notify_email_operator_id INT NOT NULL,
notify_netsend_operator_id INT NOT NULL,
notify_page_operator_id INT NOT NULL,
delete_level INT NOT NULL,
date_created DATETIME NOT NULL,
date_modified DATETIME NOT NULL,
version_number INT NOT NULL
)
CREATE UNIQUE CLUSTERED INDEX clust ON sysjobs(job_id)
CREATE NONCLUSTERED INDEX nc1 ON sysjobs(name) -- NOTE: This is deliberately non-unique
CREATE NONCLUSTERED INDEX nc3 ON sysjobs(category_id)
CREATE NONCLUSTERED INDEX nc4 ON sysjobs(owner_sid)
END
go
/**************************************************************/
/* trig_sysjobs_insert_update */
/**************************************************************/
PRINT ''
PRINT 'Creating trigger trig_sysjobs_insert_update...'
IF NOT OBJECT_ID('dbo.trig_sysjobs_insert_update', 'TR') IS NULL
DROP TRIGGER dbo.trig_sysjobs_insert_update
GO
CREATE TRIGGER dbo.trig_sysjobs_insert_update
ON dbo.sysjobs
FOR INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON
-- Disallow the insert or update if the originating_server_id isn't in sysoriginatingservers_view.
IF (EXISTS (SELECT *
FROM inserted
WHERE inserted.originating_server_id NOT IN
(SELECT v.originating_server_id
FROM sysoriginatingservers_view AS v)))
BEGIN
RAISERROR(14379, -1, -1, 'dbo.sysjobs')
ROLLBACK TRANSACTION
RETURN
END
END
go
/**************************************************************/
/* SYSJOBSERVERS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysjobservers')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysjobservers...'
CREATE TABLE sysjobservers
(
job_id UNIQUEIDENTIFIER NOT NULL,
server_id INT NOT NULL,
last_run_outcome TINYINT NOT NULL,
last_outcome_message NVARCHAR(4000) NULL,
last_run_date INT NOT NULL,
last_run_time INT NOT NULL,
last_run_duration INT NOT NULL
)
CREATE CLUSTERED INDEX clust ON sysjobservers(job_id)
CREATE NONCLUSTERED INDEX nc1 ON sysjobservers(server_id)
END
ELSE
BEGIN
ALTER TABLE sysjobservers ALTER COLUMN
last_outcome_message NVARCHAR(4000) NULL
END
go
/**************************************************************/
/* SYSJOBS_VIEW */
/**************************************************************/
PRINT ''
PRINT 'Creating view sysjobs_view...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysjobs_view')
AND (type = 'V')))
DROP VIEW sysjobs_view
go
CREATE VIEW sysjobs_view
AS
SELECT jobs.job_id,
svr.originating_server,
jobs.name,
jobs.enabled,
jobs.description,
jobs.start_step_id,
jobs.category_id,
jobs.owner_sid,
jobs.notify_level_eventlog,
jobs.notify_level_email,
jobs.notify_level_netsend,
jobs.notify_level_page,
jobs.notify_email_operator_id,
jobs.notify_netsend_operator_id,
jobs.notify_page_operator_id,
jobs.delete_level,
jobs.date_created,
jobs.date_modified,
jobs.version_number,
jobs.originating_server_id,
svr.master_server
FROM msdb.dbo.sysjobs as jobs
JOIN msdb.dbo.sysoriginatingservers_view as svr
ON jobs.originating_server_id = svr.originating_server_id
--LEFT JOIN msdb.dbo.sysjobservers js ON jobs.job_id = js.job_id
WHERE (owner_sid = SUSER_SID())
OR (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
OR (ISNULL(IS_MEMBER(N'SQLAgentReaderRole'), 0) = 1)
OR ( (ISNULL(IS_MEMBER(N'TargetServersRole'), 0) = 1) AND
(EXISTS(SELECT * FROM msdb.dbo.sysjobservers js
WHERE js.server_id <> 0 AND js.job_id = jobs.job_id))) -- filter out local jobs
go
IF (OBJECT_ID(N'dbo.syssessions', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table syssessions...'
CREATE TABLE dbo.syssessions
(
session_id INT IDENTITY PRIMARY KEY,
agent_start_date DATETIME NOT NULL
)
CREATE UNIQUE NONCLUSTERED INDEX nonclust ON syssessions(agent_start_date)
END
go
IF (OBJECT_ID(N'dbo.sysjobactivity', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table sysjobactivity...'
CREATE TABLE dbo.sysjobactivity
(
session_id INT NOT NULL REFERENCES syssessions(session_id),
job_id UNIQUEIDENTIFIER NOT NULL REFERENCES sysjobs(job_id) ON DELETE CASCADE,
run_requested_date DATETIME NULL,
run_requested_source sysname NULL,
queued_date DATETIME NULL,
start_execution_date DATETIME NULL,
last_executed_step_id INT NULL,
last_executed_step_date DATETIME NULL,
stop_execution_date DATETIME NULL,
job_history_id INT NULL, --keeps a reference to the record in sysjobhistory for detailed job information
next_scheduled_run_date DATETIME NULL
)
CREATE UNIQUE CLUSTERED INDEX clust ON sysjobactivity(session_id, job_id)
END
go
/**************************************************************/
/* SYSJOBSTEPS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysjobsteps')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysjobsteps...'
CREATE TABLE sysjobsteps
(
job_id UNIQUEIDENTIFIER NOT NULL,
step_id INT NOT NULL,
step_name sysname NOT NULL,
subsystem NVARCHAR(40) NOT NULL,
command NVARCHAR(max) NULL,
flags INT NOT NULL,
additional_parameters NVARCHAR(max) NULL,
cmdexec_success_code INT NOT NULL,
on_success_action TINYINT NOT NULL,
on_success_step_id INT NOT NULL,
on_fail_action TINYINT NOT NULL,
on_fail_step_id INT NOT NULL,
server sysname NULL, -- Used only by replication and OLAP
database_name sysname NULL,
database_user_name sysname NULL,
retry_attempts INT NOT NULL,
retry_interval INT NOT NULL,
os_run_priority INT NOT NULL, -- NOTE: Cannot use TINYINT because we need a signed number
output_file_name NVARCHAR(200) NULL,
last_run_outcome INT NOT NULL,
last_run_duration INT NOT NULL,
last_run_retries INT NOT NULL,
last_run_date INT NOT NULL,
last_run_time INT NOT NULL,
proxy_id INT NULL,
step_uid UNIQUEIDENTIFIER NULL
)
CREATE UNIQUE CLUSTERED INDEX clust ON sysjobsteps(job_id, step_id)
CREATE UNIQUE NONCLUSTERED INDEX nc1 ON sysjobsteps(job_id, step_name)
CREATE UNIQUE NONCLUSTERED INDEX nc2 ON sysjobsteps(step_uid)
END
go
/**************************************************************/
/* SYSJOBSTEPSLOGS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysjobstepslogs')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysjobstepslogs...'
CREATE TABLE sysjobstepslogs
(
log_id INT IDENTITY (1,1) PRIMARY KEY NOT NULL,
log NVARCHAR(max) NOT NULL,
date_created DATETIME NOT NULL DEFAULT getdate(),
date_modified DATETIME NOT NULL DEFAULT getdate(),
log_size bigint NOT NULL ,
step_uid UNIQUEIDENTIFIER NOT NULL REFERENCES sysjobsteps(step_uid) ON DELETE CASCADE
)
END
go
/**************************************************************/
/* SYSSCHEDULES */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysschedules')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysschedules...'
CREATE TABLE sysschedules
(
schedule_id INT IDENTITY PRIMARY KEY CLUSTERED,
schedule_uid UNIQUEIDENTIFIER NOT NULL,
originating_server_id INT NOT NULL, -- REFERENCE enforced by trig_sysschedules_insert_update
name sysname NOT NULL,
owner_sid varbinary(85) NOT NULL,
enabled INT NOT NULL,
freq_type INT NOT NULL,
freq_interval INT NOT NULL,
freq_subday_type INT NOT NULL,
freq_subday_interval INT NOT NULL,
freq_relative_interval INT NOT NULL,
freq_recurrence_factor INT NOT NULL,
active_start_date INT NOT NULL,
active_end_date INT NOT NULL,
active_start_time INT NOT NULL,
active_end_time INT NOT NULL,
date_created DATETIME NOT NULL DEFAULT (GETDATE()),
date_modified DATETIME NOT NULL DEFAULT (GETDATE()),
version_number INT NOT NULL DEFAULT (1)
)
-- CREATE UNIQUE CLUSTERED INDEX clust ON sysschedules(job_id, name)
END
go
/**************************************************************/
/* trig_sysschedules_insert_update */
/**************************************************************/
PRINT ''
PRINT 'Creating trigger trig_sysschedules_insert_update...'
IF NOT OBJECT_ID('dbo.trig_sysschedules_insert_update', 'TR') IS NULL
DROP TRIGGER dbo.trig_sysschedules_insert_update
GO
CREATE TRIGGER dbo.trig_sysschedules_insert_update
ON dbo.sysschedules
FOR INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON
-- Disallow the insert or update if the originating_server_id isn't in sysoriginatingservers_view.
IF (EXISTS (SELECT *
FROM inserted
WHERE inserted.originating_server_id NOT IN
(SELECT v.originating_server_id
FROM sysoriginatingservers_view AS v)))
BEGIN
RAISERROR(14379, -1, -1, 'dbo.sysschedules')
ROLLBACK TRANSACTION
RETURN
END
END
go
/**************************************************************/
/* SYSSCHEDULES_LOCALSERVER_VIEW */
/**************************************************************/
PRINT ''
PRINT 'Creating view sysschedules_localserver_view...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysschedules_localserver_view')
AND (type = 'V')))
DROP VIEW sysschedules_localserver_view
go
CREATE VIEW sysschedules_localserver_view
AS
SELECT sched.schedule_id,
sched.schedule_uid,
sched.originating_server_id,
sched.name,
sched.owner_sid,
sched.enabled,
sched.freq_type,
sched.freq_interval,
sched.freq_subday_type,
sched.freq_subday_interval,
sched.freq_relative_interval,
sched.freq_recurrence_factor,
sched.active_start_date,
sched.active_end_date,
sched.active_start_time,
sched.active_end_time,
sched.date_created,
sched.date_modified,
sched.version_number,
svr.originating_server,
svr.master_server
FROM msdb.dbo.sysschedules as sched
JOIN msdb.dbo.sysoriginatingservers_view as svr
ON sched.originating_server_id = svr.originating_server_id
WHERE (svr.master_server = 0)
AND ( (sched.owner_sid = SUSER_SID())
OR (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
OR (ISNULL(IS_MEMBER(N'SQLAgentReaderRole'), 0) = 1)
)
go
/**************************************************************/
/* SYSJOBSCHEDULES */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysjobschedules')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysjobschedules...'
CREATE TABLE sysjobschedules
(
schedule_id INT REFERENCES sysschedules(schedule_id),
job_id UNIQUEIDENTIFIER REFERENCES sysjobs(job_id),
next_run_date INT NOT NULL DEFAULT 0,
next_run_time INT NOT NULL DEFAULT 0
)
CREATE UNIQUE CLUSTERED INDEX clust ON sysjobschedules(job_id, schedule_id)
CREATE NONCLUSTERED INDEX [NC_sysjobschedules_schedule_id] ON sysjobschedules(schedule_id)
END
go
/**************************************************************/
/* SYSCATEGORIES */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'syscategories')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table syscategories...'
CREATE TABLE syscategories
(
category_id INT IDENTITY NOT NULL,
category_class INT NOT NULL, -- 1 = Job, 2 = Alert, 3 = Operator
category_type TINYINT NOT NULL, -- 1 = Local, 2 = Multi-Server [Only relevant if class is 1; otherwise, 3 (None)]
name sysname NOT NULL
)
CREATE UNIQUE CLUSTERED INDEX clust ON syscategories(name, category_class)
END
go
-- Install standard [permanent] categories (reserved ID range is 0 - 99)
SET IDENTITY_INSERT msdb.dbo.syscategories ON
DELETE FROM msdb.dbo.syscategories
WHERE (category_id < 100)
-- Core categories
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 0, 1, 1, N'[Uncategorized (Local)]') -- Local default
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 1, 1, 1, N'Jobs from MSX') -- All jobs downloaded from the MSX are placed in this category
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 2, 1, 2, N'[Uncategorized (Multi-Server)]') -- Multi-server default
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 3, 1, 1, N'Database Maintenance') -- Default for all jobs created by the Maintenance Plan Wizard
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 5, 1, 1, N'Full-Text') -- Default for all jobs created by the Index Server
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 6, 1, 1, N'Log Shipping') -- Default for Log Shipping jobs
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 7, 1, 1, N'Database Engine Tuning Advisor') -- Default for DTA jobs
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES ( 8, 1, 1, N'Data Collector') -- Default for all jobs created by the Data Collector
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (98, 2, 3, N'[Uncategorized]') -- Alert default
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (99, 3, 3, N'[Uncategorized]') -- Operator default
-- Replication categories
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (10, 1, 1, N'REPL-Distribution')
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (11, 1, 1, N'REPL-Distribution Cleanup')
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (12, 1, 1, N'REPL-History Cleanup')
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (13, 1, 1, N'REPL-LogReader')
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (14, 1, 1, N'REPL-Merge')
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (15, 1, 1, N'REPL-Snapshot')
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (16, 1, 1, N'REPL-Checkup')
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (17, 1, 1, N'REPL-Subscription Cleanup')
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (18, 1, 1, N'REPL-Alert Response')
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (19, 1, 1, N'REPL-QueueReader')
INSERT INTO msdb.dbo.syscategories (category_id, category_class, category_type, name) VALUES (20, 2, 3, N'Replication')
SET IDENTITY_INSERT msdb.dbo.syscategories OFF
go
/**************************************************************/
/* SYSTARGETSERVERS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'systargetservers')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table systargetservers...'
CREATE TABLE systargetservers
(
server_id INT IDENTITY NOT NULL,
server_name sysname NOT NULL,
location NVARCHAR(200) NULL,
time_zone_adjustment INT NOT NULL, -- The offset from GMT in minutes (set by sp_msx_enlist)
enlist_date DATETIME NOT NULL,
last_poll_date DATETIME NOT NULL,
status INT NOT NULL, -- 1 = Normal, 2 = Offline, 4 = Blocked
local_time_at_last_poll DATETIME NOT NULL, -- The local time at the target server as-of the last time it polled the MSX
enlisted_by_nt_user NVARCHAR(100) NOT NULL,
poll_interval INT NOT NULL -- The MSX polling interval (in seconds)
)
EXECUTE sys.sp_bindefault default_current_date, N'systargetservers.enlist_date'
EXECUTE sys.sp_bindefault default_current_date, N'systargetservers.last_poll_date'
EXECUTE sys.sp_bindefault default_one, N'systargetservers.status'
CREATE UNIQUE CLUSTERED INDEX clust ON systargetservers(server_id)
CREATE UNIQUE NONCLUSTERED INDEX nc1 ON systargetservers(server_name)
END
go
/**************************************************************/
/* SYSTARGETSERVERS_VIEW */
/**************************************************************/
PRINT ''
PRINT 'Creating view systargetservers_view...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'systargetservers_view')
AND (type = 'V')))
DROP VIEW systargetservers_view
go
CREATE VIEW systargetservers_view
AS
SELECT server_id,
server_name,
enlist_date,
last_poll_date
FROM msdb.dbo.systargetservers
UNION
SELECT 0,
CONVERT(sysname, SERVERPROPERTY('ServerName')),
CONVERT(DATETIME, N'19981113', 112),
CONVERT(DATETIME, N'19981113', 112)
go
/**************************************************************/
/* SYSTARGETSERVERGROUPS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'systargetservergroups')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table systargetservergroups...'
CREATE TABLE systargetservergroups
(
servergroup_id INT IDENTITY NOT NULL,
name sysname NOT NULL
)
CREATE UNIQUE CLUSTERED INDEX clust ON systargetservergroups(name)
END
go
/**************************************************************/
/* SYSTARGETSERVERGROUPMEMBERS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'systargetservergroupmembers')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table systargetservergroupmembers...'
CREATE TABLE systargetservergroupmembers
(
servergroup_id INT NOT NULL,
server_id INT NOT NULL
)
CREATE UNIQUE CLUSTERED INDEX clust ON systargetservergroupmembers(servergroup_id, server_id)
CREATE NONCLUSTERED INDEX nc1 ON systargetservergroupmembers(server_id)
END
go
/**************************************************************/
/* SYSALERTS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysalerts')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysalerts...'
CREATE TABLE sysalerts
(
id INT IDENTITY NOT NULL,
name sysname NOT NULL, -- Was length 60 in 6.x
event_source NVARCHAR(100) NOT NULL,
event_category_id INT NULL,
event_id INT NULL,
message_id INT NOT NULL, -- Was NULL in 6.x
severity INT NOT NULL, -- Was NULL in 6.x
enabled TINYINT NOT NULL,
delay_between_responses INT NOT NULL,
last_occurrence_date INT NOT NULL, -- Was NULL in 6.x
last_occurrence_time INT NOT NULL, -- Was NULL in 6.x
last_response_date INT NOT NULL, -- Was NULL in 6.x
last_response_time INT NOT NULL, -- Was NULL in 6.x
notification_message NVARCHAR(512) NULL,
include_event_description TINYINT NOT NULL,
database_name NVARCHAR(512) NULL,
event_description_keyword NVARCHAR(100) NULL,
occurrence_count INT NOT NULL,
count_reset_date INT NOT NULL, -- Was NULL in 6.x
count_reset_time INT NOT NULL, -- Was NULL in 6.x
job_id UNIQUEIDENTIFIER NOT NULL, -- Was NULL in 6.x
has_notification INT NOT NULL, -- New for 7.0
flags INT NOT NULL, -- Was NULL in 6.x
performance_condition NVARCHAR(512) NULL,
category_id INT NOT NULL -- New for 7.0
)
CREATE UNIQUE CLUSTERED INDEX ByName ON sysalerts(name)
CREATE UNIQUE INDEX ByID ON sysalerts(id)
END
go
/**************************************************************/
/* sysalerts_performance_counters_view */
/**************************************************************/
PRINT ''
PRINT 'Creating view sysalerts_performance_counters_view...'
go
IF (NOT OBJECT_ID(N'dbo.sysalerts_performance_counters_view', 'V') IS NULL)
DROP VIEW sysalerts_performance_counters_view
go
CREATE VIEW sysalerts_performance_counters_view
AS
-- Parse object_name 'SQLServer:Buffer Manager', exclude instance specific info; return as 'Buffer Manager'
SELECT RTRIM(SUBSTRING(pc.object_name, CHARINDEX(':', pc.object_name)+1, DATALENGTH(pc.object_name))) AS 'object_name',
RTRIM(pc.counter_name) AS 'counter_name',
CASE WHEN pc.instance_name IS NULL
THEN NULL
ELSE RTRIM(pc.instance_name)
END AS 'instance_name',
pc.cntr_value,
pc.cntr_type,
SERVERPROPERTY('ServerName') AS 'server_name'
FROM sys.dm_os_performance_counters pc
GO
/**************************************************************/
/* SYSOPERATORS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysoperators')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysoperators...'
CREATE TABLE sysoperators
(
id INT IDENTITY NOT NULL,
name sysname NOT NULL, -- Was length 50 in 6.x
enabled TINYINT NOT NULL,
email_address NVARCHAR(100) NULL,
last_email_date INT NOT NULL, -- Was NULL in 6.x
last_email_time INT NOT NULL, -- Was NULL in 6.x
pager_address NVARCHAR(100) NULL,
last_pager_date INT NOT NULL, -- Was NULL in 6.x
last_pager_time INT NOT NULL, -- Was NULL in 6.x
weekday_pager_start_time INT NOT NULL,
weekday_pager_end_time INT NOT NULL,
saturday_pager_start_time INT NOT NULL,
saturday_pager_end_time INT NOT NULL,
sunday_pager_start_time INT NOT NULL,
sunday_pager_end_time INT NOT NULL,
pager_days TINYINT NOT NULL,
netsend_address NVARCHAR(100) NULL, -- New for 7.0
last_netsend_date INT NOT NULL, -- New for 7.0
last_netsend_time INT NOT NULL, -- New for 7.0
category_id INT NOT NULL -- New for 7.0
)
CREATE UNIQUE CLUSTERED INDEX ByName ON sysoperators(name)
CREATE UNIQUE INDEX ByID ON sysoperators(id)
END
go
/**************************************************************/
/* SYSNOTIFICATIONS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysnotifications')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysnotifications...'
CREATE TABLE sysnotifications
(
alert_id INT NOT NULL,
operator_id INT NOT NULL,
notification_method TINYINT NOT NULL
)
CREATE UNIQUE CLUSTERED INDEX ByAlertIDAndOperatorID ON sysnotifications(alert_id, operator_id)
END
go
/**************************************************************/
/* SYSTASKIDS */
/* */
/* This table provides a mapping between new GUID job ID's */
/* and 6.x INT task ID's. */
/* Entries are made in this table for all existing 6.x tasks */
/* and for all new tasks added using the 7.0 version of */
/* sp_addtask. */
/* Callers of the 7.0 version of sp_helptask will ONLY see */
/* tasks [jobs] that have a corresponding entry in this table */
/* [IE. Jobs created with sp_add_job will not be returned]. */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'systaskids')
AND (type = 'U')))
BEGIN
CREATE TABLE systaskids
(
task_id INT IDENTITY NOT NULL,
job_id UNIQUEIDENTIFIER NOT NULL
)
CREATE CLUSTERED INDEX clust ON systaskids(job_id)
END
go
/**************************************************************/
/* SYSCACHEDCREDENTIALS */
/* */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'syscachedcredentials')
AND (type = 'U')))
BEGIN
CREATE TABLE syscachedcredentials
(
login_name sysname COLLATE database_default NOT NULL PRIMARY KEY,
has_server_access BIT NOT NULL DEFAULT 0,
is_sysadmin_member BIT NOT NULL DEFAULT 0,
cachedate DATETIME NOT NULL DEFAULT getdate()
)
END
go
/**************************************************************/
/* */
/* C O R E P R O C E D U R E S */
/* */
/**************************************************************/
PRINT ''
PRINT 'Creating function SQLAGENT_SUSER_SNAME ...'
IF (NOT OBJECT_ID(N'dbo.SQLAGENT_SUSER_SNAME', 'FN') IS NULL)
DROP FUNCTION dbo.SQLAGENT_SUSER_SNAME
go
CREATE FUNCTION dbo.SQLAGENT_SUSER_SNAME(@user_sid VARBINARY(85)) RETURNS sysname
AS
BEGIN
DECLARE @ret sysname
IF @user_sid = 0xFFFFFFFF
SELECT @ret = N'$(SQLAgentAccount)'
ELSE
SELECT @ret = SUSER_SNAME(@user_sid)
RETURN @ret
END
go
PRINT ''
PRINT 'Creating function SQLAGENT_SUSER_SID ...'
IF (NOT OBJECT_ID(N'dbo.SQLAGENT_SUSER_SID', 'FN') IS NULL)
DROP FUNCTION dbo.SQLAGENT_SUSER_SID
go
CREATE FUNCTION dbo.SQLAGENT_SUSER_SID(@user_name sysname) RETURNS VARBINARY(85)
AS
BEGIN
DECLARE @ret VARBINARY(85)
IF @user_name = N'$(SQLAgentAccount)'
SELECT @ret = 0xFFFFFFFF
ELSE
SELECT @ret = SUSER_SID(@user_name, 0)
RETURN @ret
END
go
-----------------------------------------------------------
-- get_principal_id : retrieves principal_id for a given sid
--
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.get_principal_id', 'FN') IS NULL
DROP FUNCTION dbo.get_principal_id
GO
CREATE FUNCTION dbo.get_principal_id(@principal_sid varbinary(85))
RETURNS int
AS
BEGIN
DECLARE @principal_id int
SELECT @principal_id=principal_id FROM msdb.sys.database_principals WHERE sid=@principal_sid
RETURN @principal_id
END
GO
-----------------------------------------------------------
-- get_principal_sid : retrieves principal sid from principal_id
--
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.get_principal_sid', 'FN') IS NULL
DROP FUNCTION dbo.get_principal_sid
GO
CREATE FUNCTION dbo.get_principal_sid(@principal_id int)
RETURNS varbinary(85)
AS
BEGIN
DECLARE @principal_sid varbinary(85)
SELECT @principal_sid=sid FROM msdb.sys.database_principals WHERE principal_id=@principal_id
RETURN @principal_sid
END
GO
/**************************************************************/
/* SP_SQLAGENT_IS_SRVROLEMEMBER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure SP_SQLAGENT_IS_SRVROLEMEMBER...'
IF (NOT OBJECT_ID(N'dbo.sp_sqlagent_is_srvrolemember', 'P') IS NULL)
DROP PROCEDURE dbo.sp_sqlagent_is_srvrolemember
go
CREATE PROCEDURE sp_sqlagent_is_srvrolemember
@role_name sysname, @login_name sysname
AS
BEGIN
DECLARE @is_member INT
SET NOCOUNT ON
IF @role_name IS NULL OR @login_name IS NULL
RETURN(0)
SELECT @is_member = 0
--IS_SRVROLEMEMBER works only if the login to be tested is provisioned with sqlserver
if( @login_name = SUSER_SNAME())
SELECT @is_member = IS_SRVROLEMEMBER(@role_name)
else
SELECT @is_member = IS_SRVROLEMEMBER(@role_name, @login_name)
--try to impersonate. A try catch is used because we can have @name as NT groups also
IF @is_member IS NULL
BEGIN
BEGIN TRY
if( is_srvrolemember('sysadmin') = 1)
begin
EXECUTE AS LOGIN = @login_name -- impersonate
SELECT @is_member = IS_SRVROLEMEMBER(@role_name) -- check role membership
REVERT -- revert back
end
END TRY
BEGIN CATCH
SELECT @is_member = 0
END CATCH
END
RETURN ISNULL(@is_member,0)
END
go
/**************************************************************/
/* SP_VERIFY_CATEGORY_IDENTIFIERS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_category_identifiers...'
IF (NOT OBJECT_ID(N'dbo.sp_verify_category_identifiers', 'P') IS NULL)
DROP PROCEDURE dbo.sp_verify_category_identifiers
go
CREATE PROCEDURE sp_verify_category_identifiers
@name_of_name_parameter [varchar](60),
@name_of_id_parameter [varchar](60),
@category_name [sysname] OUTPUT,
@category_id [INT] OUTPUT
AS
BEGIN
DECLARE @retval INT
DECLARE @category_id_as_char NVARCHAR(36)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name_of_name_parameter = LTRIM(RTRIM(@name_of_name_parameter))
SELECT @name_of_id_parameter = LTRIM(RTRIM(@name_of_id_parameter))
SELECT @category_name = LTRIM(RTRIM(@category_name))
IF (@category_name = N'') SELECT @category_name = NULL
IF ((@category_name IS NOT NULL) AND (@category_id IS NOT NULL))
BEGIN
RAISERROR(14524, -1, -1, @name_of_id_parameter, @name_of_name_parameter)
RETURN(1) -- Failure
END
-- Check category id
IF (@category_id IS NOT NULL)
BEGIN
SELECT @category_name = name
FROM msdb.dbo.syscategories
WHERE (category_id = @category_id)
IF (@category_name IS NULL)
BEGIN
SELECT @category_id_as_char = CONVERT(nvarchar(36), @category_id)
RAISERROR(14262, -1, -1, '@category_id', @category_id_as_char)
RETURN(1) -- Failure
END
END
ELSE
-- Check category name
IF (@category_name IS NOT NULL)
BEGIN
-- The name is not ambiguous, so get the corresponding category_id (if the job exists)
SELECT @category_id = category_id
FROM msdb.dbo.syscategories
WHERE (name = @category_name)
IF (@category_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@category_name', @category_name)
RETURN(1) -- Failure
END
END
RETURN(0) -- Success
END
go
PRINT ''
PRINT 'Creating function agent_datetime...'
IF (NOT OBJECT_ID(N'dbo.agent_datetime', 'FN') IS NULL)
DROP FUNCTION dbo.agent_datetime
go
CREATE FUNCTION agent_datetime(@date int, @time int)
RETURNS DATETIME
AS
BEGIN
RETURN
(
CONVERT(DATETIME,
CONVERT(NVARCHAR(4),@date / 10000) + N'-' +
CONVERT(NVARCHAR(2),(@date % 10000)/100) + N'-' +
CONVERT(NVARCHAR(2),@date % 100) + N' ' +
CONVERT(NVARCHAR(2),@time / 10000) + N':' +
CONVERT(NVARCHAR(2),(@time % 10000)/100) + N':' +
CONVERT(NVARCHAR(2),@time % 100),
120)
)
END
go
/**************************************************************/
/* SP_VERIFY_PROXY_IDENTIFIERS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_proxy_identifiers...'
IF (NOT OBJECT_ID(N'dbo.sp_verify_proxy_identifiers', 'P') IS NULL)
DROP PROCEDURE dbo.sp_verify_proxy_identifiers
go
CREATE PROCEDURE sp_verify_proxy_identifiers
@name_of_name_parameter [varchar](60),
@name_of_id_parameter [varchar](60),
@proxy_name [sysname] OUTPUT,
@proxy_id [INT] OUTPUT
AS
BEGIN
DECLARE @retval INT
DECLARE @proxy_id_as_char NVARCHAR(36)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name_of_name_parameter = LTRIM(RTRIM(@name_of_name_parameter))
SELECT @name_of_id_parameter = LTRIM(RTRIM(@name_of_id_parameter))
SELECT @proxy_name = LTRIM(RTRIM(@proxy_name))
IF (@proxy_name = N'') SELECT @proxy_name = NULL
IF ((@proxy_name IS NULL) AND (@proxy_id IS NULL)) OR
((@proxy_name IS NOT NULL) AND (@proxy_id IS NOT NULL))
BEGIN
RAISERROR(14524, -1, -1, @name_of_id_parameter, @name_of_name_parameter)
RETURN(1) -- Failure
END
-- Check proxy id
IF (@proxy_id IS NOT NULL)
BEGIN
SELECT @proxy_name = name
FROM msdb.dbo.sysproxies
WHERE (proxy_id = @proxy_id)
IF (@proxy_name IS NULL)
BEGIN
SELECT @proxy_id_as_char = CONVERT(nvarchar(36), @proxy_id)
RAISERROR(14262, -1, -1, @name_of_id_parameter, @proxy_id_as_char)
RETURN(1) -- Failure
END
END
ELSE
-- Check proxy name
IF (@proxy_name IS NOT NULL)
BEGIN
-- The name is not ambiguous, so get the corresponding proxy_id (if the job exists)
SELECT @proxy_id = proxy_id
FROM msdb.dbo.sysproxies
WHERE (name = @proxy_name)
IF (@proxy_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, @name_of_name_parameter, @proxy_name)
RETURN(1) -- Failure
END
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_VERIFY_CREDENTIAL_IDENTIFIERS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_credential_identifiers...'
IF (NOT OBJECT_ID(N'dbo.sp_verify_credential_identifiers', 'P') IS NULL)
DROP PROCEDURE dbo.sp_verify_credential_identifiers
go
CREATE PROCEDURE sp_verify_credential_identifiers
@name_of_name_parameter [varchar](60),
@name_of_id_parameter [varchar](60),
@credential_name [sysname] OUTPUT,
@credential_id [INT] OUTPUT,
@allow_only_windows_credential bit = NULL
AS
BEGIN
DECLARE @retval INT
DECLARE @credential_id_as_char NVARCHAR(36)
DECLARE @credential_identity NVARCHAR(4000)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name_of_name_parameter = LTRIM(RTRIM(@name_of_name_parameter))
SELECT @name_of_id_parameter = LTRIM(RTRIM(@name_of_id_parameter))
SELECT @credential_name = LTRIM(RTRIM(@credential_name))
IF (@credential_name = N'') SELECT @credential_name = NULL
IF ((@credential_name IS NULL) AND (@credential_id IS NULL)) OR
((@credential_name IS NOT NULL) AND (@credential_id IS NOT NULL))
BEGIN
RAISERROR(14524, -1, -1, @name_of_id_parameter, @name_of_name_parameter)
RETURN(1) -- Failure
END
-- Check credential_id
IF (@credential_id IS NOT NULL)
BEGIN
SELECT @credential_name = name,
@credential_identity = credential_identity
FROM sys.credentials
WHERE (credential_id = @credential_id)
IF (@credential_name IS NULL)
BEGIN
SELECT @credential_id_as_char = CONVERT(nvarchar(36), @credential_id)
RAISERROR(14262, -1, -1, '@credential_id', @credential_id_as_char)
RETURN(1) -- Failure
END
END
ELSE
-- Check credential name
IF (@credential_name IS NOT NULL)
BEGIN
-- The name is not ambiguous, so get the corresponding credential_id (if the job exists)
SELECT @credential_id = credential_id,
@credential_identity = credential_identity
FROM sys.credentials
WHERE (name = @credential_name)
IF (@credential_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@credential_name', @credential_name)
RETURN(1) -- Failure
END
END
IF(@allow_only_windows_credential IS NOT NULL)
BEGIN
IF(@allow_only_windows_credential = 1)
BEGIN
-- Allow only windows credentials. ( domain\user format)
IF(CHARINDEX(N'\', @credential_identity) = 0)
BEGIN
RAISERROR(14720, -1, -1, '@credential_name', @credential_name)
RETURN(1) -- Failure
END
END
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* sp_verify_subsystems */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_subsystems...'
IF (NOT OBJECT_ID(N'dbo.sp_verify_subsystems', 'P') IS NULL)
DROP PROCEDURE dbo.sp_verify_subsystems
go
CREATE PROCEDURE dbo.sp_verify_subsystems
@syssubsytems_refresh_needed BIT = 0
AS
BEGIN
SET NOCOUNT ON
DECLARE @retval INT
DECLARE @InstRootPath nvarchar(512)
DECLARE @VersionRootPath nvarchar(512)
DECLARE @ComRootPath nvarchar(512)
DECLARE @DtsRootPath nvarchar(512)
DECLARE @SQLPSPath nvarchar(512)
DECLARE @DTExec nvarchar(512)
DECLARE @DTExecExists INT
DECLARE @ToolsPath nvarchar(512)
IF ( (@syssubsytems_refresh_needed=1) OR (NOT EXISTS(select * from syssubsystems)) )
BEGIN
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\MSSQLServer\Setup', N'SQLBinRoot', @InstRootPath OUTPUT
IF @InstRootPath IS NULL
BEGIN
RAISERROR(14658, -1, -1) WITH LOG
RETURN (1)
END
IF RIGHT(@InstRootPath, 1) <> N'\'
SELECT @InstRootPath = @InstRootPath + N'\'
EXEC master.dbo.xp_regread N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\Microsoft Sql Server\110', N'VerSpecificRootDir', @VersionRootPath OUTPUT
IF @VersionRootPath IS NULL
BEGIN
RAISERROR(14659, -1, -1) WITH LOG
RETURN(1)
END
EXEC master.dbo.xp_regread N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\Microsoft SQL Server\110\SSIS\Setup\DTSPath', N'', @DtsRootPath OUTPUT, N'no_output'
IF (@DtsRootPath IS NOT NULL)
BEGIN
SELECT @DtsRootPath = @DtsRootPath + N'Binn\'
SELECT @DTExec = @DtsRootPath + N'DTExec.exe'
CREATE TABLE #t (file_exists int, is_directory int, parent_directory_exists int)
INSERT #t EXEC xp_fileexist @DTExec
SELECT TOP 1 @DTExecExists=file_exists from #t
DROP TABLE #t
IF ((@DTExecExists IS NULL) OR (@DTExecExists = 0))
SET @DtsRootPath = NULL
END
SELECT @ComRootPath = @VersionRootPath + N'COM\'
create table #Platform(ID int, Name sysname, Internal_Value int NULL, Value nvarchar(512))
insert #Platform exec master.dbo.xp_msver 'Platform'
if EXISTS(select * from #Platform where Value like '%64%')
EXEC master.dbo.xp_regread N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Wow6432Node\Microsoft\Microsoft Sql Server\110\Tools\ClientSetup', N'SQLPath', @ToolsPath OUTPUT
else
EXEC master.dbo.xp_regread N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\Microsoft Sql Server\110\Tools\ClientSetup', N'SQLPath', @ToolsPath OUTPUT
drop table #Platform
SELECT @SQLPSPath = @ToolsPath + N'\Binn\SQLPS.exe'
-- Procedure must start its own transaction if we don't have one already.
DECLARE @TranCounter INT;
SET @TranCounter = @@TRANCOUNT;
IF @TranCounter = 0
BEGIN
BEGIN TRANSACTION;
END
-- Fix for #525111 - when MSDB is restored from any other sqlserver, it is possible that physical path to agent_exe, subsystem_dll may not be valid on current server
-- It is better to delete all records in this table and reinsert them again
-- perform delete and re-insert operations within a transaction
TRUNCATE TABLE syssubsystems
-- Obtain processor count to determine maximum number of threads per subsystem
DECLARE @xp_results TABLE
(
id INT NOT NULL,
name NVARCHAR(30) COLLATE database_default NOT NULL,
internal_value INT NULL,
character_value NVARCHAR(212) COLLATE database_default NULL
)
INSERT INTO @xp_results
EXECUTE master.dbo.xp_msver
DECLARE @processor_count INT
SELECT @processor_count = internal_value from @xp_results where id=16 -- ProcessorCount
-- Modify database.
BEGIN TRY
--create subsystems
--TSQL subsystem
INSERT syssubsystems
VALUES
(
1, N'TSQL',14556, FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), FORMATMESSAGE(14557), 20 * @processor_count
)
--ActiveScripting subsystem
INSERT syssubsystems
VALUES
(
2, N'ActiveScripting', 14555, @InstRootPath + N'SQLATXSS.DLL',NULL,N'ActiveScriptStart',N'ActiveScriptEvent',N'ActiveScriptStop', 10 * @processor_count
)
--CmdExec subsystem
INSERT syssubsystems
VALUES
(
3, N'CmdExec', 14550, @InstRootPath + N'SQLCMDSS.DLL',NULL,N'CmdExecStart',N'CmdEvent',N'CmdExecStop', 10 * @processor_count
)
--Snapshot subsystem
INSERT syssubsystems
VALUES
(
4, N'Snapshot', 14551, @InstRootPath + N'SQLREPSS.DLL', @ComRootPath + N'SNAPSHOT.EXE', N'ReplStart',N'ReplEvent',N'ReplStop',100 * @processor_count
)
--LogReader subsystem
INSERT syssubsystems
VALUES
(
5, N'LogReader', 14552, @InstRootPath + N'SQLREPSS.DLL', @ComRootPath + N'logread.exe',N'ReplStart',N'ReplEvent',N'ReplStop',25 * @processor_count
)
--Distribution subsystem
INSERT syssubsystems
VALUES
(
6, N'Distribution', 14553, @InstRootPath + N'SQLREPSS.DLL', @ComRootPath + N'DISTRIB.EXE',N'ReplStart',N'ReplEvent',N'ReplStop',100 * @processor_count
)
--Merge subsystem
INSERT syssubsystems
VALUES
(
7, N'Merge', 14554, @InstRootPath + N'SQLREPSS.DLL',@ComRootPath + N'REPLMERG.EXE',N'ReplStart',N'ReplEvent',N'ReplStop',100 * @processor_count
)
--QueueReader subsystem
INSERT syssubsystems
VALUES
(
8, N'QueueReader', 14581, @InstRootPath + N'SQLREPSS.dll',@ComRootPath + N'qrdrsvc.exe',N'ReplStart',N'ReplEvent',N'ReplStop',100 * @processor_count
)
--ANALYSISQUERY subsystem
INSERT syssubsystems
VALUES
(
9, N'ANALYSISQUERY', 14513, @InstRootPath + N'SQLOLAPSS.DLL',NULL,N'OlapStart',N'OlapQueryEvent',N'OlapStop',100 * @processor_count
)
--ANALYSISCOMMAND subsystem
INSERT syssubsystems
VALUES
(
10, N'ANALYSISCOMMAND', 14514, @InstRootPath + N'SQLOLAPSS.DLL',NULL,N'OlapStart',N'OlapCommandEvent',N'OlapStop',100 * @processor_count
)
IF(@DtsRootPath IS NOT NULL)
BEGIN
--DTS subsystem
INSERT syssubsystems
VALUES
(
11, N'SSIS', 14538, @InstRootPath + N'SQLDTSSS.DLL',@DtsRootPath + N'DTExec.exe',N'DtsStart',N'DtsEvent',N'DtsStop',100 * @processor_count
)
END
--PowerShell subsystem
INSERT syssubsystems
VALUES
(
12, N'PowerShell', 14698, @InstRootPath + N'SQLPOWERSHELLSS.DLL', @SQLPSPath, N'PowerShellStart',N'PowerShellEvent',N'PowerShellStop',2
)
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(400)
DECLARE @ErrorSeverity INT
DECLARE @ErrorState INT
SELECT @ErrorMessage = ERROR_MESSAGE()
SELECT @ErrorSeverity = ERROR_SEVERITY()
SELECT @ErrorState = ERROR_STATE()
-- Roll back the transaction that we started if we are not nested
IF @TranCounter = 0
BEGIN
ROLLBACK TRANSACTION;
END
-- if we are nested inside another transaction just raise the
-- error and let the outer transaction do the rollback
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
)
RETURN (1)
END CATCH
END --(NOT EXISTS(select * from syssubsystems))
-- commit the transaction we started
IF @TranCounter = 0
BEGIN
COMMIT TRANSACTION;
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* sp_verify_subsystem_identifiers */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_subsystem_identifiers...'
IF (NOT OBJECT_ID(N'dbo.sp_verify_subsystem_identifiers', 'P') IS NULL)
DROP PROCEDURE dbo.sp_verify_subsystem_identifiers
go
CREATE PROCEDURE dbo.sp_verify_subsystem_identifiers
@name_of_name_parameter [varchar](60),
@name_of_id_parameter [varchar](60),
@subsystem_name [sysname] OUTPUT,
@subsystem_id [INT] OUTPUT
AS
BEGIN
DECLARE @retval INT
DECLARE @subsystem_id_as_char NVARCHAR(36)
SET NOCOUNT ON
-- this call will populate subsystems table if necessary
EXEC @retval = msdb.dbo.sp_verify_subsystems
IF @retval <> 0
RETURN(@retval)
-- Remove any leading/trailing spaces from parameters
SELECT @name_of_name_parameter = LTRIM(RTRIM(@name_of_name_parameter))
SELECT @name_of_id_parameter = LTRIM(RTRIM(@name_of_id_parameter))
SELECT @subsystem_name = LTRIM(RTRIM(@subsystem_name))
IF (@subsystem_name = N'') SELECT @subsystem_name = NULL
IF ((@subsystem_name IS NULL) AND (@subsystem_id IS NULL)) OR
((@subsystem_name IS NOT NULL) AND (@subsystem_id IS NOT NULL))
BEGIN
RAISERROR(14524, -1, -1, @name_of_id_parameter, @name_of_name_parameter)
RETURN(1) -- Failure
END
-- Check subsystem_id
IF (@subsystem_id IS NOT NULL)
BEGIN
SELECT @subsystem_name = subsystem
FROM msdb.dbo.syssubsystems
WHERE (subsystem_id = @subsystem_id)
IF (@subsystem_name IS NULL)
BEGIN
SELECT @subsystem_id_as_char = CONVERT(nvarchar(36), @subsystem_id)
RAISERROR(14262, -1, -1, '@subsystem_id', @subsystem_id_as_char)
RETURN(1) -- Failure
END
END
ELSE
-- Check subsystem name
IF (@subsystem_name IS NOT NULL)
BEGIN
-- Make sure Dts is translated into new subsystem's name SSIS
IF UPPER(@subsystem_name collate SQL_Latin1_General_CP1_CS_AS) = N'DTS'
BEGIN
SET @subsystem_name = N'SSIS'
END
-- The name is not ambiguous, so get the corresponding subsystem_id (if the subsystem exists)
SELECT @subsystem_id = subsystem_id
FROM msdb.dbo.syssubsystems
WHERE (UPPER(subsystem collate SQL_Latin1_General_CP1_CS_AS) = UPPER(@subsystem_name collate SQL_Latin1_General_CP1_CS_AS))
IF (@subsystem_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@subsystem_name', @subsystem_name)
RETURN(1) -- Failure
END
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* sp_verify_login_identifiers */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_login_identifiers...'
IF (NOT OBJECT_ID(N'dbo.sp_verify_login_identifiers', 'P') IS NULL)
DROP PROCEDURE dbo.sp_verify_login_identifiers
go
CREATE PROCEDURE dbo.sp_verify_login_identifiers
@login_name [nvarchar](256),
@fixed_server_role [nvarchar](256),
@msdb_role [nvarchar](256),
@name [nvarchar](256) OUTPUT,
@sid varbinary(85) OUTPUT,
@flags INT OUTPUT
AS
BEGIN
DECLARE @retval INT
DECLARE @raise_error bit
SET NOCOUNT ON
SELECT @flags = -1, @raise_error = 0
SELECT @sid = NULL
IF @login_name IS NOT NULL
BEGIN
--check validity
--use the new optional parameter of SUSER_SID to have a case insensitive comparation for NT users
SELECT @sid = SUSER_SID(@login_name, 0)
IF @sid IS NULL
BEGIN
RAISERROR(14520, -1, -1, @login_name)
RETURN(1) -- Failure
END
SELECT @name = @login_name, @flags = 0
END
IF COALESCE(@login_name, @fixed_server_role, @msdb_role) IS NULL
BEGIN
RAISERROR(14519, -1, -1)
RETURN(1) -- Failure
END
IF @fixed_server_role IS NOT NULL AND @flags <> -1
SELECT @raise_error = 1
ELSE IF @fixed_server_role IS NOT NULL
--check validity
BEGIN
-- IS_SRVROLEMEMBER return NULL for an invalid server role
IF ISNULL(IS_SRVROLEMEMBER(@fixed_server_role), -1) = -1
BEGIN
RAISERROR(14521, -1, -1, @fixed_server_role)
RETURN(1) -- Failure
END
SELECT @name = @fixed_server_role, @flags = 1
SELECT @sid = SUSER_SID(@fixed_server_role)
END
IF @msdb_role IS NOT NULL AND @flags <> -1
SELECT @raise_error = 1
ELSE IF @msdb_role IS NOT NULL
BEGIN
--check the correctness of msdb role
IF ISNULL(IS_MEMBER(@msdb_role), -1) = -1
BEGIN
RAISERROR(14522, -1, -1, @msdb_role)
RETURN(1) -- Failure
END
SELECT @sid = sid from sys.database_principals
WHERE UPPER(@msdb_role collate SQL_Latin1_General_CP1_CS_AS) = UPPER(name collate SQL_Latin1_General_CP1_CS_AS)
AND type = 'R'
IF @sid IS NULL
BEGIN
RAISERROR(14522, -1, -1, @msdb_role)
RETURN(1) -- Failure
END
SELECT @name = @msdb_role, @flags = 2
END
IF @raise_error = 1
BEGIN
RAISERROR(14519, -1, -1)
RETURN(1) -- Failure
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_VERIFY_PROXY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_proxy...'
IF (NOT OBJECT_ID(N'dbo.sp_verify_proxy', 'P') IS NULL)
DROP PROCEDURE dbo.sp_verify_proxy
go
CREATE PROCEDURE dbo.sp_verify_proxy
@proxy_id [INT] = NULL,
@proxy_name [sysname],
@enabled [tinyint],
@description [nvarchar](512) = NULL
AS
BEGIN
DECLARE @return_code INT
SET NOCOUNT ON
-- Check if the NewName is unique
IF (EXISTS ( SELECT *
FROM msdb.dbo.sysproxies
WHERE (name = @proxy_name) AND
proxy_id <> ISNULL(@proxy_id,0) ))
BEGIN
RAISERROR(14261, 16, 1, '@name', @proxy_name)
RETURN(1) -- Failure
END
-- Enabled must be 0 or 1
IF (@enabled NOT IN (0, 1))
BEGIN
RAISERROR(14266, 16, 1, '@enabled', '0, 1')
RETURN(1) -- Failure
END
RETURN(0)
END
go
/**************************************************************/
/* SP_ADD_PROXY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_proxy...'
IF (NOT OBJECT_ID(N'dbo.sp_add_proxy', 'P') IS NULL)
DROP PROCEDURE dbo.sp_add_proxy
go
CREATE PROCEDURE dbo.sp_add_proxy
@proxy_name [sysname],
@enabled [tinyint] = 1,
@description [nvarchar](512) = NULL,
@credential_name [sysname] = NULL,
@credential_id [INT] = NULL,
@proxy_id [int] = NULL OUTPUT
AS
BEGIN
DECLARE @retval INT
DECLARE @full_name NVARCHAR(257) --two sysnames + \
DECLARE @user_sid VARBINARY(85)
DECLARE @cred_date_time DATETIME
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @proxy_name = LTRIM(RTRIM(@proxy_name))
SELECT @description = LTRIM(RTRIM(@description))
IF @proxy_name = '' SELECT @proxy_name = NULL
IF @description = '' SELECT @description = NULL
EXECUTE @retval = sp_verify_proxy NULL,
@proxy_name,
@enabled,
@description
IF (@retval <> 0)
RETURN(1) -- Failure
EXECUTE @retval = sp_verify_credential_identifiers '@credential_name',
'@credential_id',
@credential_name OUTPUT,
@credential_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- warn if the user_domain\user_name does not exist
SELECT @full_name = credential_identity, @cred_date_time = create_date from master.sys.credentials
WHERE credential_id = @credential_id
--force case insensitive comparation for NT users
SELECT @user_sid = SUSER_SID(@full_name,0)
IF @user_sid IS NULL
BEGIN
RAISERROR(14529, -1, -1, @full_name)
RETURN(1)
END
-- Finally, do the actual INSERT
INSERT INTO msdb.dbo.sysproxies
(
name,
credential_id,
enabled,
description,
user_sid,
credential_date_created
)
VALUES
(
@proxy_name,
@credential_id,
@enabled,
@description,
@user_sid,
@cred_date_time
)
--get newly created proxy_id;
SELECT @proxy_id = SCOPE_IDENTITY()
END
go
/**************************************************************/
/* SP_DELETE_PROXY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_proxy...'
IF (NOT OBJECT_ID(N'dbo.sp_delete_proxy', 'P') IS NULL)
DROP PROCEDURE dbo.sp_delete_proxy
go
CREATE PROCEDURE dbo.sp_delete_proxy
@proxy_id int = NULL,
@proxy_name sysname = NULL
-- must specify only one of above parameters to identify the proxy
AS
BEGIN
DECLARE @retval INT
SET NOCOUNT ON
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
--no jobsteps should use this proxy
IF EXISTS (SELECT * FROM sysjobsteps
WHERE @proxy_id = proxy_id)
BEGIN
RAISERROR(14518, -1, -1, @proxy_id)
RETURN(1) -- Failure
END
BEGIN TRANSACTION
--delete any association between subsystems and this proxy
DELETE sysproxysubsystem
WHERE proxy_id = @proxy_id
--delete any association between logins and this proxy
DELETE sysproxylogin
WHERE proxy_id = @proxy_id
-- delete the entry in sysproxies table
DELETE sysproxies
WHERE proxy_id = @proxy_id
COMMIT
RETURN(0)
END
go
/**************************************************************/
/* SP_UPDATE_PROXY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_proxy...'
IF (NOT OBJECT_ID(N'dbo.sp_update_proxy', 'P') IS NULL)
DROP PROCEDURE dbo.sp_update_proxy
go
CREATE PROCEDURE dbo.sp_update_proxy
@proxy_id [int] = NULL,
@proxy_name [sysname] = NULL,
-- must specify only one of above parameter identify the proxy
@credential_name [sysname] = NULL,
@credential_id [INT] = NULL,
@new_name [sysname] = NULL,
@enabled [tinyint] = NULL,
@description [nvarchar](512) = NULL
AS
BEGIN
DECLARE @x_new_name [sysname]
DECLARE @x_credential_id [int]
DECLARE @x_enabled [tinyint]
DECLARE @x_description [nvarchar](512)
DECLARE @x_credential_date_created [datetime]
DECLARE @user_sid VARBINARY(85)
DECLARE @full_name [sysname] --two sysnames + \
DECLARE @retval INT
SET NOCOUNT ON
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
IF @credential_id IS NOT NULL OR @credential_name IS NOT NULL
BEGIN
EXECUTE @retval = sp_verify_credential_identifiers '@credential_name',
'@credential_id',
@credential_name OUTPUT,
@credential_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Remove any leading/trailing spaces from parameters
SELECT @new_name = LTRIM(RTRIM(@new_name))
SELECT @description = LTRIM(RTRIM(@description))
-- Turn [nullable] empty string parameters into NULLs
IF @new_name = '' SELECT @new_name = NULL
IF @description = '' SELECT @description = NULL
-- Set the x_ (existing) variables
SELECT @x_new_name = name,
@x_credential_id = credential_id,
@x_enabled = enabled,
@x_description = description,
@x_credential_date_created = credential_date_created
FROM sysproxies
WHERE proxy_id = @proxy_id
--get the new date from credential table
IF (@credential_id IS NOT NULL)
SELECT @x_credential_date_created = create_date FROM master.sys.credentials
WHERE credential_id = @credential_id
-- Fill out the values for all non-supplied parameters from the existing values
IF (@new_name IS NULL) SELECT @new_name = @x_new_name
IF (@credential_id IS NULL) SELECT @credential_id = @x_credential_id
IF (@enabled IS NULL) SELECT @enabled = @x_enabled
IF (@description IS NULL) SELECT @description = @x_description
-- warn if the user_domain\user_name does not exist
SELECT @full_name = credential_identity from master.sys.credentials
WHERE credential_id = @credential_id
--force case insensitive comparation for NT users
SELECT @user_sid = SUSER_SID(@full_name, 0)
IF @user_sid IS NULL
BEGIN
RAISERROR(14529, -1, -1, @full_name)
RETURN(1)
END
-- Finally, do the actual UPDATE
UPDATE msdb.dbo.sysproxies
SET
name = @new_name,
credential_id = @credential_id,
user_sid = @user_sid,
enabled = @enabled,
description = @description,
credential_date_created = @x_credential_date_created --@x_ is OK in this case
WHERE proxy_id = @proxy_id
END
go
/**************************************************************/
/* SP_SQLAGENT_IS_MEMBER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sqlagent_is_member...'
IF (NOT OBJECT_ID(N'dbo.sp_sqlagent_is_member', 'P') IS NULL)
DROP PROCEDURE dbo.sp_sqlagent_is_member
go
-- check if a login is member of NT group\database role
--
-- if we specify a NT group SID @login_sid should be NOT NULL
--
-- if a @role_principal_id is specified, a NULL login is allowed
-- in this case we check if the msdb database user associated
-- with the current security context is member of the specified
-- msdb database role (this allows us to verify if a particular
-- msdb database loginless msdb user is member of that msdb role)
CREATE PROCEDURE dbo.sp_sqlagent_is_member
(
@group_sid VARBINARY(85) = NULL,
@role_principal_id INT = NULL,
@login_sid VARBINARY(85)
)
AS
BEGIN
DECLARE @ret_success INT
DECLARE @login NVARCHAR(256)
DECLARE @impersonated INT
DECLARE @group_name NVARCHAR(256)
SELECT @ret_success = 0 --failure
SELECT @impersonated = 0
IF (@group_sid IS NOT NULL AND @login_sid IS NULL)
RETURN(0)
--a sysadmin can check for every user group membership
IF (@login_sid IS NOT NULL) AND (ISNULL(IS_SRVROLEMEMBER('sysadmin'),0) = 1)
BEGIN
--get login name from principal_id
SELECT @login = SUSER_SNAME(@login_sid)
IF SUSER_SNAME() <> @login
BEGIN
--impersonate
EXECUTE sp_setuserbylogin @login
SELECT @impersonated = 1
END
END
IF @group_sid IS NOT NULL
SELECT @group_name = SUSER_SNAME(@group_sid)
ELSE
SELECT @group_name = USER_NAME(@role_principal_id)
-- return success, if login is member of the group, and failure if group doesnt exist or login is not member of the group
SELECT @ret_success = ISNULL(IS_MEMBER(@group_name),0)
--revert to self
IF @impersonated = 1
EXECUTE sp_setuserbylogin
RETURN @ret_success
END
go
/**************************************************************/
/* sp_verify_proxy_permissions */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_proxy_permissions...'
IF (NOT OBJECT_ID(N'dbo.sp_verify_proxy_permissions', 'P') IS NULL)
DROP PROCEDURE dbo.sp_verify_proxy_permissions
go
CREATE PROCEDURE dbo.sp_verify_proxy_permissions
@subsystem_name sysname,
@proxy_id INT = NULL,
@name NVARCHAR(256) = NULL,
@raise_error INT = 1,
@allow_disable_proxy INT = 0,
@verify_special_account INT = 0,
@check_only_read_perm INT = 0
AS
BEGIN
DECLARE @retval INT
DECLARE @granted_sid VARBINARY(85)
DECLARE @is_member INT
DECLARE @is_sysadmin BIT
DECLARE @flags TINYINT
DECLARE @enabled TINYINT
DECLARE @name_sid VARBINARY(85)
DECLARE @role_from_sid sysname
DECLARE @name_from_sid sysname
DECLARE @is_SQLAgentOperatorRole BIT
DECLARE @check_only_subsystem BIT
DECLARE proxy_subsystem CURSOR LOCAL
FOR
SELECT p.sid, p.flags
FROM sysproxyloginsubsystem_view p, syssubsystems s
WHERE p.proxy_id = @proxy_id AND p.subsystem_id = s.subsystem_id
AND UPPER(s.subsystem collate SQL_Latin1_General_CP1_CS_AS) =
UPPER(@subsystem_name collate SQL_Latin1_General_CP1_CS_AS)
SET NOCOUNT ON
SELECT @retval = 1
IF @proxy_id IS NULL
RETURN(0)
-- TSQL subsystem prohibited
IF (UPPER(@subsystem_name collate SQL_Latin1_General_CP1_CS_AS) = N'TSQL')
BEGIN
RAISERROR(14517, -1, -1)
RETURN(1) -- Failure
END
--check if the date stored inside proxy still exists and match the cred create_date inside proxy
--otherwise the credential has been tempered from outside
--if so, disable proxy and continue execution
--only a sysadmin caller have cross database permissions but
--when executing by sqlagent this check will be always performed
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
BEGIN
IF NOT EXISTS(SELECT * FROM sysproxies p JOIN master.sys.credentials c ON p.credential_id = c.credential_id
WHERE p.proxy_id = @proxy_id AND p.credential_date_created = c.create_date AND enabled=1)
BEGIN
UPDATE sysproxies SET enabled=0 WHERE proxy_id = @proxy_id
END
END
--if no login has been passed check permission against the caller
IF @name IS NULL
SELECT @name = SUSER_SNAME()
--check if the proxy is disable and continue or not based on
--allow_disable_proxy
--allow creation of a job step with a disabled proxy but
--sqlagent always call with @allow_disable_proxy = 0
SELECT @enabled = enabled FROM sysproxies WHERE proxy_id = @proxy_id
IF (@enabled = 0) AND (@allow_disable_proxy = 0)
BEGIN
RAISERROR(14537, -1, -1, @proxy_id)
RETURN(2) -- Failure
END
--we need to check permission only against subsystem in following cases
--1. @name is sysadmin
--2. @name is member of SQLAgentOperatorRole and @check_only_read_perm=1
--3. @verify_special_account =1
--sysadmin and SQLAgentOperatorRole have permission to view all proxies
IF (@verify_special_account = 1)
SET @check_only_subsystem = 1
ELSE
BEGIN
EXEC @is_sysadmin = sp_sqlagent_is_srvrolemember N'sysadmin', @name
IF (@is_sysadmin = 1)
SET @check_only_subsystem = 1
ELSE
BEGIN
EXEC @is_SQLAgentOperatorRole = sp_sqlagent_is_srvrolemember N'SQLAgentOperatorRole', @name -- check role membership
IF ((@is_SQLAgentOperatorRole = 1) AND (@check_only_read_perm = 1))
SET @check_only_subsystem = 1
END
END
IF (@check_only_subsystem = 1)
BEGIN
IF NOT EXISTS(SELECT * FROM sysproxysubsystem sp JOIN syssubsystems s ON sp.subsystem_id = s.subsystem_id
WHERE proxy_id = @proxy_id AND UPPER(s.subsystem collate SQL_Latin1_General_CP1_CS_AS) =
UPPER(@subsystem_name collate SQL_Latin1_General_CP1_CS_AS))
BEGIN
IF (@raise_error <> 0)
BEGIN
RAISERROR(14516, -1, -1, @proxy_id, @subsystem_name, @name)
END
RETURN(1) -- Failure
END
RETURN(0)
END
--get SID from name; we verify if a login has permission to use a certain proxy
--force case insensitive comparation for NT users
SELECT @name_sid = SUSER_SID(@name, 0)
--check first if name has been granted explicit permissions
IF (@name_sid IS NOT NULL)
BEGIN
IF EXISTS(SELECT * FROM sysproxyloginsubsystem_view p, syssubsystems s
WHERE p.proxy_id = @proxy_id AND p.subsystem_id = s.subsystem_id
AND UPPER(s.subsystem collate SQL_Latin1_General_CP1_CS_AS) =
UPPER(@subsystem_name collate SQL_Latin1_General_CP1_CS_AS)
AND
p.sid = @name_sid) -- name has been granted explicit permissions
BEGIN
RETURN(0)
END
END
OPEN proxy_subsystem
FETCH NEXT FROM proxy_subsystem INTO @granted_sid, @flags
WHILE (@@fetch_status = 0 AND @retval = 1)
BEGIN
IF @flags = 0 AND @granted_sid IS NOT NULL AND @name_sid IS NOT NULL -- NT GROUP
BEGIN
EXEC @is_member = sp_sqlagent_is_member @group_sid = @granted_sid, @login_sid = @name_sid
IF @is_member = 1
SELECT @retval = 0
END
ELSE IF @flags = 2 AND @granted_sid IS NOT NULL -- MSDB role (@name_sid can be null in case of a loginless user member of msdb)
BEGIN
DECLARE @principal_id INT
SET @principal_id = msdb.dbo.get_principal_id(@granted_sid)
EXEC @is_member = sp_sqlagent_is_member @role_principal_id = @principal_id, @login_sid = @name_sid
IF @is_member = 1
SELECT @retval = 0
END
ELSE IF (@flags = 1) AND @granted_sid IS NOT NULL AND @name_sid IS NOT NULL -- FIXED SERVER Roles
BEGIN
-- we have to use impersonation to check for role membership
SELECT @role_from_sid = SUSER_SNAME(@granted_sid)
SELECT @name_from_sid = SUSER_SNAME(@name_sid)
EXEC @is_member = sp_sqlagent_is_srvrolemember @role_from_sid, @name_from_sid -- check role membership
IF @is_member = 1
SELECT @retval = 0
END
IF @retval = 1
BEGIN
SELECT @granted_sid = NULL
FETCH NEXT FROM proxy_subsystem INTO @granted_sid, @flags
END
END
DEALLOCATE proxy_subsystem
IF (@retval = 1 AND @raise_error <> 0)
BEGIN
RAISERROR(14516, -1, -1, @proxy_id, @subsystem_name, @name)
RETURN(1) -- Failure
END
--0 is for success
RETURN @retval
END
go
/**************************************************************/
/* SP_HELP_PROXY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_proxy...'
IF (NOT OBJECT_ID(N'dbo.sp_help_proxy', 'P') IS NULL)
DROP PROCEDURE dbo.sp_help_proxy
go
CREATE PROCEDURE dbo.sp_help_proxy
@proxy_id int = NULL,
@proxy_name sysname = NULL,
@subsystem_name sysname = NULL,
@name nvarchar(256) = NULL
AS
BEGIN
DECLARE @retval INT
DECLARE @subsystem_id INT
DECLARE @cur_subsystem_name NVARCHAR(40)
DECLARE @current_proxy_id INT
DECLARE @not_have_permission INT
DECLARE cur_proxy CURSOR LOCAL
FOR
SELECT p.proxy_id, s.subsystem
FROM sysproxies p, syssubsystems s
WHERE ISNULL(UPPER(@subsystem_name collate SQL_Latin1_General_CP1_CS_AS),
UPPER(s.subsystem collate SQL_Latin1_General_CP1_CS_AS) ) =
UPPER(s.subsystem collate SQL_Latin1_General_CP1_CS_AS) AND
s.subsystem_id <> 1 --last is TSQL subsystem
-- this call will populate subsystems table if necessary
EXEC @retval = msdb.dbo.sp_verify_subsystems
IF @retval <> 0
RETURN(1) --failure
--create temp table with returned rows
DECLARE @temp_proxy TABLE
(
proxy_id INT --used to identify a proxy
)
SET NOCOUNT ON
SELECT @subsystem_id = NULL
-- Remove any leading/trailing spaces from parameters
SELECT @proxy_name = LTRIM(RTRIM(@proxy_name))
IF @proxy_name = '' SELECT @proxy_name = NULL
SELECT @subsystem_name = LTRIM(RTRIM(@subsystem_name))
IF @proxy_name = '' SELECT @proxy_name = NULL
SELECT @name = LTRIM(RTRIM(@name))
IF @name = '' SELECT @name = NULL
IF (@proxy_id IS NOT NULL OR @proxy_name IS NOT NULL)
BEGIN
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
IF @subsystem_name IS NOT NULL
BEGIN
EXECUTE @retval = sp_verify_subsystem_identifiers '@subsystem_name',
'@subsystem_id',
@subsystem_name OUTPUT,
@subsystem_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
IF (@subsystem_name IS NOT NULL AND @name IS NULL) OR
(@subsystem_name IS NULL AND @name IS NOT NULL)
BEGIN
RAISERROR(14532, -1, -1, '@subsystem_name', '@name')
RETURN(1) -- Failure
END
--only member of sysadmin and SQLAgentOperatorRole roles can see proxies granted to somebody else
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND
(ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) = 0))
BEGIN
SELECT @name = SUSER_SNAME()
END
IF @name IS NOT NULL
BEGIN
OPEN cur_proxy
FETCH NEXT FROM cur_proxy INTO @current_proxy_id, @cur_subsystem_name
WHILE (@@fetch_status = 0)
BEGIN
--verify if supplied user have permission to use the current proxy for specified subsystem
--disabled proxy should be shown as well
IF NOT EXISTS(SELECT * FROM @temp_proxy WHERE proxy_id = @current_proxy_id)
BEGIN
EXECUTE @not_have_permission = sp_verify_proxy_permissions
@subsystem_name = @cur_subsystem_name,
@proxy_id = @current_proxy_id,
@name = @name,
@raise_error = 0,
@allow_disable_proxy = 1,
@verify_special_account = 0,
@check_only_read_perm = 1
IF (@not_have_permission = 0) -- have permissions
INSERT @temp_proxy VALUES(@current_proxy_id)
END
FETCH NEXT FROM cur_proxy INTO @current_proxy_id, @cur_subsystem_name
END
CLOSE cur_proxy
DEALLOCATE cur_proxy
END
ELSE
INSERT @temp_proxy SELECT proxy_id from sysproxies
-- returns different result sets if caller is admin or not
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR
(ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) = 1))
BEGIN
SELECT p.proxy_id,
p.name,
c.credential_identity,
p.enabled,
p.description,
p.user_sid,
p.credential_id,
CASE WHEN c.credential_id IS NULL THEN 0 ELSE 1 END as credential_identity_exists
FROM sysproxies p LEFT JOIN master.sys.credentials c ON p.credential_id = c.credential_id
JOIN @temp_proxy t ON p.proxy_id = t.proxy_id
WHERE ISNULL(@proxy_id, p.proxy_id) = p.proxy_id
END
ELSE
BEGIN
SELECT p.proxy_id, p.name, null as credential_identity, p.enabled, p.description, null as user_sid, p.credential_id, null as credential_identity_exists
FROM sysproxies p, @temp_proxy t
WHERE ISNULL(@proxy_id, p.proxy_id) = p.proxy_id AND
p.proxy_id = t.proxy_id
END
END
go
/**************************************************************/
/* sp_get_proxy_properties */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_get_proxy_properties...'
GO
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_get_proxy_properties')
AND (type = 'P')))
DROP PROCEDURE sp_get_proxy_properties
GO
CREATE PROCEDURE sp_get_proxy_properties
@proxy_id [int] = NULL, -- specify either @current_proxy_id or @current_proxy_name ; if both are specified as null, propery for all proxies are returned back
@proxy_name [sysname] = NULL
AS
BEGIN
DECLARE @retval INT
SET NOCOUNT ON
-- Validate only if either proxy name or proxy id was specified
IF NOT (@proxy_id IS NULL ) AND (@proxy_name IS NULL)
BEGIN
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
BEGIN
-- exception message was raised inside sp_verify_proxy_identifiers; we dont need to RAISERROR again here
RETURN(1) -- Failure
END
END
-- return domain name, user name, credential id; used by SQL agent to query for proxy
SELECT CASE CHARINDEX(N'\', c.credential_identity)
WHEN 0 THEN NULL
ELSE LEFT(c.credential_identity, CHARINDEX(N'\', c.credential_identity)-1)
END
AS user_domain,
RIGHT(c.credential_identity, LEN(c.credential_identity)- CHARINDEX(N'\', c.credential_identity)) AS user_name,
c.credential_id
FROM msdb.dbo.sysproxies p JOIN
sys.credentials c
ON p.credential_id = c.credential_id
WHERE (p.proxy_id = @proxy_id OR @proxy_id IS NULL)
END
GO
/**************************************************************/
/* sp_grant_proxy_to_subsystem */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_grant_proxy_to_subsystem...'
IF (NOT OBJECT_ID(N'dbo.sp_grant_proxy_to_subsystem', 'P') IS NULL)
DROP PROCEDURE dbo.sp_grant_proxy_to_subsystem
go
CREATE PROCEDURE dbo.sp_grant_proxy_to_subsystem
@proxy_id int = NULL,
@proxy_name sysname = NULL,
-- must specify only one of above parameter to identify the proxy
@subsystem_id int = NULL,
@subsystem_name sysname = NULL
-- must specify only one of above parameter to identify the subsystem
AS
BEGIN
DECLARE @retval INT
DECLARE @proxy_account sysname
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @subsystem_name = LTRIM(RTRIM(@subsystem_name))
SELECT @proxy_name = LTRIM(RTRIM(@proxy_name))
-- Turn [nullable] empty string parameters into NULLs
IF @subsystem_name = '' SELECT @subsystem_name = NULL
IF @proxy_name = '' SELECT @proxy_name = NULL
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
EXECUTE @retval = sp_verify_subsystem_identifiers '@subsystem_name',
'@subsystem_id',
@subsystem_name OUTPUT,
@subsystem_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
--TSQL subsystem is prohibited
IF @subsystem_id = 1
BEGIN
RAISERROR(14530, -1, -1)
RETURN(1) -- Failure
END
--check if we already added an user for the pair subsystem-proxy
IF (EXISTS(SELECT * FROM sysproxysubsystem WHERE subsystem_id = @subsystem_id
AND proxy_id = @proxy_id))
BEGIN
RAISERROR(14531, -1, -1)
RETURN(1) -- Failure
END
-- For CmdExec and Powershell subsystems, make sure that proxy is mapped to windows login
IF ((UPPER(@subsystem_name collate SQL_Latin1_General_CP1_CS_AS) = 'CMDEXEC') OR
(UPPER(@subsystem_name collate SQL_Latin1_General_CP1_CS_AS) = 'POWERSHELL'))
BEGIN
DECLARE @credential_name [sysname]
DECLARE @credential_id [INT]
SELECT @credential_id = credential_id FROM sysproxies
WHERE proxy_id = @proxy_id
EXECUTE @retval = sp_verify_credential_identifiers '@credential_name',
'@credential_id',
@credential_name OUTPUT,
@credential_id OUTPUT,
@allow_only_windows_credential = 1
IF (@retval <> 0)
BEGIN
RETURN(1) -- Failure
END
END
INSERT INTO sysproxysubsystem
( subsystem_id, proxy_id )
VALUES
( @subsystem_id, @proxy_id )
END
go
/**************************************************************/
/* sp_grant_login_to_proxy */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_grant_login_to_proxy...'
IF (NOT OBJECT_ID(N'dbo.sp_grant_login_to_proxy', 'P') IS NULL)
DROP PROCEDURE dbo.sp_grant_login_to_proxy
go
CREATE PROCEDURE dbo.sp_grant_login_to_proxy
@login_name NVARCHAR(256) = NULL,
@fixed_server_role NVARCHAR(256) = NULL,
@msdb_role NVARCHAR(256) = NULL,
-- must specify only one of above parameter to identify the type of login
@proxy_id int = NULL,
@proxy_name sysname = NULL
-- must specify only one of above parameter to identify the proxy
AS
BEGIN
DECLARE @retval INT
DECLARE @name nvarchar(256)
DECLARE @flags INT
DECLARE @sid VARBINARY(85)
DECLARE @is_sysadmin BIT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @proxy_name = LTRIM(RTRIM(@proxy_name))
SELECT @fixed_server_role = LTRIM(RTRIM(@fixed_server_role))
SELECT @msdb_role = LTRIM(RTRIM(@msdb_role))
-- Turn [nullable] empty string parameters into NULLs
IF @proxy_name = '' SELECT @proxy_name = NULL
IF @login_name = '' SELECT @login_name = NULL
IF @fixed_server_role = '' SELECT @fixed_server_role = NULL
IF @msdb_role = '' SELECT @msdb_role = NULL
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
EXECUTE @retval = sp_verify_login_identifiers @login_name,
@fixed_server_role,
@msdb_role,
@name OUTPUT,
@sid OUTPUT,
@flags OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- is login member of sysadmin role?
SELECT @is_sysadmin = 0
IF (@login_name IS NOT NULL)
BEGIN
EXEC @is_sysadmin = sp_sqlagent_is_srvrolemember N'sysadmin', @login_name -- check role membership
END
IF (@is_sysadmin = 1)
BEGIN
-- @name is sysadmin, it cannot granted to proxy
-- issue a message and do nothing
RAISERROR(14395, 10, 1, @name)
END
ELSE
BEGIN
--check if we already added an user for the pair subsystem-proxy
IF (EXISTS(SELECT * FROM sysproxylogin WHERE proxy_id = @proxy_id
AND ISNULL(sid, 0) = ISNULL(@sid,0)
AND flags = @flags))
BEGIN
RAISERROR(14531, -1, -1)
RETURN(1) -- Failure
END
INSERT INTO sysproxylogin
( proxy_id, sid, flags )
VALUES
( @proxy_id, @sid, @flags)
END
END
go
/**************************************************************/
/* sp_revoke_login_from_proxy */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_revoke_login_from_proxy...'
IF (NOT OBJECT_ID(N'dbo.sp_revoke_login_from_proxy', 'P') IS NULL)
DROP PROCEDURE dbo.sp_revoke_login_from_proxy
go
CREATE PROCEDURE dbo.sp_revoke_login_from_proxy
@name NVARCHAR(256),
@proxy_id INT = NULL,
@proxy_name sysname = NULL
-- must specify only one of above parameter to identify the proxy
AS
BEGIN
DECLARE @retval INT
DECLARE @sid VARBINARY(85)
DECLARE @is_sysadmin BIT
DECLARE @flags INT
DECLARE @affected_records INT = 0
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @proxy_name = LTRIM(RTRIM(@proxy_name))
SELECT @name = LTRIM(RTRIM(@name))
-- Turn [nullable] empty string parameters into NULLs
IF @proxy_name = '' SELECT @proxy_name = NULL
IF @name = '' SELECT @name = NULL
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- is login member of sysadmin role?
SELECT @is_sysadmin = 0
IF (@name IS NOT NULL)
BEGIN
EXEC @is_sysadmin = sp_sqlagent_is_srvrolemember N'sysadmin', @name -- check role membership
END
IF (@is_sysadmin = 1)
BEGIN
-- @name is sysadmin, it cannot be revoked from proxy
-- issue a message and do nothing
RAISERROR(14395, 10, -1, @name)
RETURN(1) -- Failure
END
ELSE
BEGIN
DECLARE revoke_cursor CURSOR LOCAL
FOR
SELECT flags FROM sysproxylogin WHERE proxy_id = @proxy_id
OPEN revoke_cursor
FETCH NEXT FROM revoke_cursor INTO @flags
WHILE (@@fetch_status = 0)
BEGIN
if @flags = 1 OR @flags = 0 -- @flags with value 1 indicates fixed server role, flags with value 0 indicates login, both sid(s) should be read from sys.server_principals
SELECT @sid = SUSER_SID(@name, 0) --force case insensitive comparation for NT users
ELSE
SELECT @sid = sid FROM msdb.sys.database_principals WHERE name = @name -- @flags with value 2 indicates MSDB role
--check parametrs validity
IF (ISNULL(@sid, 0) <> 0)
BEGIN
DELETE FROM sysproxylogin WHERE
proxy_id = @proxy_id AND
sid = @sid AND
flags = @flags
SELECT @affected_records = @affected_records + @@ROWCOUNT
END
FETCH NEXT FROM revoke_cursor INTO @flags
END
CLOSE revoke_cursor
DEALLOCATE revoke_cursor
if @affected_records = 0
BEGIN
RAISERROR(14523, -1, -1, @name, @proxy_name)
RETURN(1) -- Failure
END
END
RETURN(0)
END
go
/**************************************************************/
/* sp_revoke_proxy_from_subsystem */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_revoke_proxy_from_subsystem...'
IF (NOT OBJECT_ID(N'dbo.sp_revoke_proxy_from_subsystem', 'P') IS NULL)
DROP PROCEDURE dbo.sp_revoke_proxy_from_subsystem
go
CREATE PROCEDURE dbo.sp_revoke_proxy_from_subsystem
@proxy_id INT = NULL,
@proxy_name sysname = NULL,
-- must specify only one of above parameter to identify the proxyAS
@subsystem_id INT = NULL,
@subsystem_name sysname = NULL
-- must specify only one of above parameter to identify the subsystem
AS
BEGIN
DECLARE @retval INT
DECLARE @proxy_account sysname
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @subsystem_name = LTRIM(RTRIM(@subsystem_name))
SELECT @proxy_name = LTRIM(RTRIM(@proxy_name))
-- Turn [nullable] empty string parameters into NULLs
IF @subsystem_name = '' SELECT @subsystem_name = NULL
IF @proxy_name = '' SELECT @proxy_name = NULL
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
EXECUTE @retval = sp_verify_subsystem_identifiers '@subsystem_name',
'@subsystem_id',
@subsystem_name OUTPUT,
@subsystem_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
--check parametrs validity
IF (EXISTS(SELECT * FROM sysproxysubsystem WHERE
subsystem_id = @subsystem_id AND
proxy_id = @proxy_id ))
BEGIN
DELETE FROM sysproxysubsystem WHERE
subsystem_id = @subsystem_id AND
proxy_id = @proxy_id
END
ELSE
BEGIN
RAISERROR(14600, -1, -1, @proxy_name, @subsystem_name)
RETURN(1) -- Failure
END
RETURN(0)
END
go
/**************************************************************/
/* SP_ENUM_PROXY_FOR_SUBSYSTEM */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_enum_proxy_for_subsystem...'
IF (NOT OBJECT_ID(N'dbo.sp_enum_proxy_for_subsystem', 'P') IS NULL)
DROP PROCEDURE dbo.sp_enum_proxy_for_subsystem
go
CREATE PROCEDURE sp_enum_proxy_for_subsystem
@proxy_id int = NULL,
@proxy_name sysname = NULL,
-- must specify only one of above parameter to identify the proxy or none
@subsystem_id int = NULL,
@subsystem_name sysname = NULL
-- must specify only one of above parameter to identify the subsystem or none
AS
BEGIN
DECLARE @retval INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @subsystem_name = LTRIM(RTRIM(@subsystem_name))
SELECT @proxy_name = LTRIM(RTRIM(@proxy_name))
-- Turn [nullable] empty string parameters into NULLs
IF @subsystem_name = '' SELECT @subsystem_name = NULL
IF @proxy_name = '' SELECT @proxy_name = NULL
IF @proxy_name IS NOT NULL OR @proxy_id IS NOT NULL
BEGIN
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
IF @subsystem_name IS NOT NULL OR @subsystem_id IS NOT NULL
BEGIN
EXECUTE @retval = sp_verify_subsystem_identifiers '@subsystem_name',
'@subsystem_id',
@subsystem_name OUTPUT,
@subsystem_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
SELECT ps.subsystem_id AS subsystem_id, s.subsystem AS subsystem_name, ps.proxy_id AS proxy_id, p.name AS proxy_name
FROM sysproxysubsystem ps JOIN sysproxies p ON ps.proxy_id = p.proxy_id
JOIN syssubsystems s ON ps.subsystem_id = s.subsystem_id
WHERE
ISNULL(@subsystem_id, ps.subsystem_id) = ps.subsystem_id AND
ISNULL(@proxy_id, ps.proxy_id ) = ps.proxy_id
END
go
/**************************************************************/
/* sp_enum_login_for_proxy */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_enum_login_for_proxy...'
IF (NOT OBJECT_ID(N'dbo.sp_enum_login_for_proxy', 'P') IS NULL)
DROP PROCEDURE dbo.sp_enum_login_for_proxy
go
CREATE PROCEDURE sp_enum_login_for_proxy
@name NVARCHAR(256) = NULL,
@proxy_id INT = NULL,
@proxy_name sysname = NULL
-- must specify only one of above parameter to identify the proxy or none
AS
BEGIN
DECLARE @retval INT
DECLARE @sid VARBINARY(85)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @proxy_name = LTRIM(RTRIM(@proxy_name))
SELECT @name = LTRIM(RTRIM(@name))
-- Turn [nullable] empty string parameters into NULLs
IF @proxy_name = '' SELECT @proxy_name = NULL
IF @name = '' SELECT @name = NULL
IF @proxy_name IS NOT NULL OR @proxy_id IS NOT NULL
BEGIN
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
IF (@name IS NOT NULL) AND
--force case insensitive comparation for NT users
(ISNULL(SUSER_SID(@name, 0), 0) = 0) AND
(ISNULL(IS_SRVROLEMEMBER(@name), -1) = -1) AND
(ISNULL(IS_MEMBER(@name), -1) = -1)
BEGIN
RAISERROR(14520, -1, -1, @name)
RETURN(1) -- Failure
END
--force case insensitive comparation for NT users
SELECT @sid = SUSER_SID(@name, 0)
IF @sid IS NULL -- then @name is a MSDB role
SELECT @sid = sid FROM sys.database_principals
WHERE name = @name
SELECT pl.proxy_id AS proxy_id, p.name AS proxy_name, pl.flags as flags,
CASE pl.flags
WHEN 0 THEN SUSER_SNAME(pl.sid) -- SQLLOGIN, NT USER/GROUP
WHEN 1 THEN SUSER_SNAME(pl.sid) -- SQL fixed server role
WHEN 2 THEN USER_NAME(msdb.dbo.get_principal_id(pl.sid)) -- MSDB role
ELSE NULL -- should never be the case
END AS name, pl.sid AS sid, msdb.dbo.get_principal_id(pl.sid) AS principal_id
FROM sysproxylogin pl JOIN sysproxies p ON pl.proxy_id = p.proxy_id
WHERE
COALESCE(@proxy_id, pl.proxy_id, 0 ) = ISNULL(pl.proxy_id, 0) AND
COALESCE(@sid, pl.sid, 0 ) = ISNULL(pl.sid, 0)
END
go
/**************************************************************/
/* sp_reassign_proxy */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_reassign_proxy...'
GO
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_reassign_proxy')
AND (type = 'P')))
DROP PROCEDURE sp_reassign_proxy
GO
CREATE PROCEDURE sp_reassign_proxy
@current_proxy_id [int] = NULL, -- must specify either @current_proxy_id or @current_proxy_name
@current_proxy_name [sysname] = NULL,
@target_proxy_id [int] = NULL, -- must specify either @target_proxy_id or @target_proxy_name
@target_proxy_name [sysname] = NULL -- N'' is a special case to allow change of an existing proxy as NULL (run job step in sql agent service account context)
AS
BEGIN
DECLARE @retval INT
SET NOCOUNT ON
-- validate current proxy id
EXECUTE @retval = sp_verify_proxy_identifiers '@current_proxy_name',
'@current_proxy_id',
@current_proxy_name OUTPUT,
@current_proxy_id OUTPUT
IF (@retval <> 0)
BEGIN
-- exception message was raised inside sp_verify_proxy_identifiers; we dont need to RAISERROR again here
RETURN(1) -- Failure
END
-- @target_proxy_name = N'' is a special case to allow change of an existing proxy as NULL (run job step in sql agent service account context)
IF (@target_proxy_id IS NOT NULL) OR (@target_proxy_name IS NOT NULL AND @target_proxy_name <> N'')
BEGIN
EXECUTE @retval = sp_verify_proxy_identifiers '@target_proxy_name',
'@target_proxy_id',
@target_proxy_name OUTPUT,
@target_proxy_id OUTPUT
IF (@retval <> 0)
BEGIN
-- exception message was raised inside sp_verify_proxy_identifiers; we dont need to RAISERROR again here
RETURN(1) -- Failure
END
END
-- Validate that current proxy id and target proxy id are not the same
IF(@current_proxy_id = @target_proxy_id)
BEGIN
RAISERROR(14399, -1, -1, @current_proxy_id, @target_proxy_id)
RETURN(1) -- Failure
END
DECLARE @job_id UNIQUEIDENTIFIER
DECLARE @step_id int
DECLARE @proxy_id int
DECLARE @subsystem_id int
-- cursor to enumerate list of job steps what has proxy_id as current proxy_id
DECLARE @jobstep_cursor CURSOR
SET @jobstep_cursor = CURSOR FOR
SELECT js.job_id, js.step_id, js.proxy_id , subsys.subsystem_id
FROM sysjobsteps js
JOIN syssubsystems subsys ON js.subsystem = subsys.subsystem
WHERE js.proxy_id = @current_proxy_id
OPEN @jobstep_cursor
FETCH NEXT FROM @jobstep_cursor INTO @job_id, @step_id, @proxy_id, @subsystem_id
WHILE @@FETCH_STATUS = 0
BEGIN
-- current proxy might have been granted to be used by this specific subsystem
-- making sure that the target proxy has been granted access to same subsystem
-- Grant target proxy to subsystem if it was not granted before
IF NOT EXISTS( SELECT DISTINCT ps.proxy_id, subsyst.subsystem_id
FROM syssubsystems subsyst
JOIN sysproxysubsystem ps ON (ps.subsystem_id = subsyst.subsystem_id
AND ps.proxy_id = @target_proxy_id
AND ps.subsystem_id = @subsystem_id)
)
BEGIN
-- throw error that user needs to grant permission to this target proxy
IF @target_proxy_id IS NOT NULL
BEGIN
RAISERROR(14400, -1, -1, @target_proxy_id, @subsystem_id)
RETURN(1) -- Failure
END
END
-- Update proxy_id for job step with target proxy id using sp_update_jobstep
EXEC sp_update_jobstep @job_id = @job_id, @step_id = @step_id , @proxy_name = @target_proxy_name
FETCH NEXT FROM @jobstep_cursor INTO @job_id, @step_id, @proxy_id, @subsystem_id
END
CLOSE @jobstep_cursor
DEALLOCATE @jobstep_cursor
RETURN(0)
END
GO
/**************************************************************/
/* SP_SQLAGENT_GET_STARTUP_INFO */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sqlagent_get_startup_info...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_sqlagent_get_startup_info')
AND (type = 'P')))
DROP PROCEDURE sp_sqlagent_get_startup_info
go
CREATE PROCEDURE sp_sqlagent_get_startup_info
AS
BEGIN
DECLARE @tbu INT
DECLARE @agentAllowed INT
SET NOCOUNT ON
IF (ServerProperty('InstanceName') IS NULL)
BEGIN
EXECUTE @tbu = master.dbo.xp_qv '1338198028'
EXECUTE @agentAllowed = master.dbo.xp_qv '2858542058'
END
ELSE
BEGIN
DECLARE @instancename NVARCHAR(128)
SELECT @instancename = CONVERT(NVARCHAR(128), ServerProperty('InstanceName'))
EXECUTE @tbu = master.dbo.xp_qv '1338198028', @instancename
EXECUTE @agentAllowed = master.dbo.xp_qv '2858542058', @instancename
END
IF (@tbu < 0)
SELECT @tbu = 0
IF (@agentAllowed < 0)
SELECT @agentAllowed = 0
SELECT (SELECT CASE WHEN compatibility_level >= 70 THEN 1 ELSE 0 END FROM sys.databases WHERE (name = 'msdb')) AS msdb_70_compatible,
CASE WHEN DATABASEPROPERTYEX('msdb', 'Updateability') = 'READ_ONLY' THEN 1 ELSE 0 END AS msdb_read_only,
( CASE WHEN DATABASEPROPERTYEX('msdb', 'Status') = 'ONLINE' THEN 1 ELSE 0 END &
CASE WHEN DATABASEPROPERTYEX('msdb', 'UserAccess') = 'MULTI_USER' THEN 1 ELSE 0 END) AS msdb_available,
CASE ISNULL((SELECT 1 WHERE 'a' = 'A'), 0)
WHEN 1 THEN 0
ELSE 1
END AS case_sensitive_server,
(SELECT value_in_use FROM sys.configurations WHERE (name = 'user connections')) AS max_user_connection,
CONVERT(sysname, SERVERPROPERTY('SERVERNAME')) AS sql_server_name,
ISNULL(@tbu, 0) AS tbu,
PLATFORM() AS platform,
ISNULL(CONVERT(sysname, SERVERPROPERTY('INSTANCENAME')), 'MSSQLSERVER') AS instance_name ,
CONVERT(INT, SERVERPROPERTY('ISCLUSTERED')) AS is_clustered,
@agentAllowed AS agent_allowed
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_SQLAGENT_UPDATE_AGENT_XPS */
/* Sql Agent uses the XPs listed in the "Agent XPs" bucket. */
/* The configuration is enable on agent startup, */
/* and disabled on agent shutdown. */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sqlagent_update_agent_xps...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_sqlagent_update_agent_xps')
AND (type = 'P')))
DROP PROCEDURE sp_sqlagent_update_agent_xps
go
CREATE PROCEDURE sp_sqlagent_update_agent_xps
@new_value bit = 1 -- the new value for the "Agent XPs" configuration option.
AS
BEGIN
declare @agent_enabled bit
declare @show_advanced bit
select @show_advanced = cast(value_in_use as bit)
from sys.configurations
where name = N'show advanced options'
select @agent_enabled = cast(value_in_use as bit)
from sys.configurations
where name = N'Agent XPs'
if @new_value <> @agent_enabled
begin
if 1 <> @show_advanced
begin
exec sys.sp_configure @configname = N'show advanced options', @configvalue = 1
reconfigure with override
end
exec sys.sp_configure @configname = N'Agent XPs', @configvalue = @new_value
reconfigure with override
if 1 <> @show_advanced
begin
exec sys.sp_configure @configname = N'show advanced options', @configvalue = 0
reconfigure with override
end
end
END
go
/**************************************************************/
/* SP_SQLAGENT_HAS_SERVER_ACCESS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sqlagent_has_server_access...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_sqlagent_has_server_access')
AND (type = 'P')))
DROP PROCEDURE sp_sqlagent_has_server_access
go
CREATE PROCEDURE sp_sqlagent_has_server_access
@login_name sysname = NULL,
@job_id uniqueidentifier = NULL, -- if this is not null, @login_name will be ignored!
@is_sysadmin_member INT = NULL OUTPUT
AS
BEGIN
DECLARE @has_server_access BIT
DECLARE @is_sysadmin BIT
DECLARE @actual_login_name sysname
-- Set only when login_name is actually found. It will be zero when @actual_login_name is (unknown).
DECLARE @login_found BIT
DECLARE @cachedate DATETIME
SET NOCOUNT ON
SELECT @cachedate = NULL
-- remove expired entries from the cache
DELETE msdb.dbo.syscachedcredentials
WHERE DATEDIFF(MINUTE, cachedate, GETDATE()) >= 29
-- query the cache
SELECT @is_sysadmin = is_sysadmin_member,
@has_server_access = has_server_access,
@cachedate = cachedate
FROM msdb.dbo.syscachedcredentials
WHERE login_name = @login_name
AND DATEDIFF(MINUTE, cachedate, GETDATE()) < 29
IF (@cachedate IS NOT NULL)
BEGIN
-- no output variable
IF (@is_sysadmin_member IS NULL)
BEGIN
-- Return result row
SELECT has_server_access = @has_server_access,
is_sysadmin = @is_sysadmin,
actual_login_name = @login_name
RETURN
END
ELSE
BEGIN
SELECT @is_sysadmin_member = @is_sysadmin
RETURN
END
END -- select from cache
-- Set defaults
SELECT @has_server_access = 0
SELECT @is_sysadmin = 0
SELECT @actual_login_name = FORMATMESSAGE(14205)
SELECT @login_found = 0
-- If @job_id was set, get the current name associated with the job owner sid.
if (@job_id IS NOT NULL)
BEGIN
SELECT @login_name = dbo.SQLAGENT_SUSER_SNAME(owner_sid)
FROM msdb.dbo.sysjobs_view
WHERE @job_id = job_id
-- If the job_id is invalid, return error
IF (@login_name IS NULL)
BEGIN
RETURN 1;
END
END
IF (@login_name IS NULL)
BEGIN
SELECT has_server_access = 1,
is_sysadmin = IS_SRVROLEMEMBER(N'sysadmin'),
actual_login_name = SUSER_SNAME()
RETURN
END
IF (@login_name LIKE '%\%')
BEGIN
-- Handle the LocalSystem account ('NT AUTHORITY\SYSTEM') as a special case
IF (UPPER(@login_name collate SQL_Latin1_General_CP1_CS_AS) = N'NT AUTHORITY\SYSTEM')
BEGIN
IF (EXISTS (SELECT *
FROM master.dbo.syslogins
WHERE (UPPER(loginname collate SQL_Latin1_General_CP1_CS_AS) = N'NT AUTHORITY\SYSTEM')))
BEGIN
SELECT @has_server_access = hasaccess,
@is_sysadmin = sysadmin,
@actual_login_name = loginname
FROM master.dbo.syslogins
WHERE (UPPER(loginname collate SQL_Latin1_General_CP1_CS_AS) = N'NT AUTHORITY\SYSTEM')
SET @login_found = 1
END
ELSE
IF (EXISTS (SELECT *
FROM master.dbo.syslogins
WHERE (UPPER(loginname collate SQL_Latin1_General_CP1_CS_AS) = N'BUILTIN\ADMINISTRATORS')))
BEGIN
SELECT @has_server_access = hasaccess,
@is_sysadmin = sysadmin,
@actual_login_name = loginname
FROM master.dbo.syslogins
WHERE (UPPER(loginname collate SQL_Latin1_General_CP1_CS_AS) = N'BUILTIN\ADMINISTRATORS')
SET @login_found = 1
END
END
ELSE
BEGIN
-- Check if the NT login has been explicitly denied access
IF (EXISTS (SELECT *
FROM master.dbo.syslogins
WHERE (loginname = @login_name)
AND (denylogin = 1)))
BEGIN
SELECT @has_server_access = 0,
@is_sysadmin = sysadmin,
@actual_login_name = loginname
FROM master.dbo.syslogins
WHERE (loginname = @login_name)
SET @login_found = 1
END
ELSE
BEGIN
-- declare table variable for storing results
DECLARE @xp_results TABLE
(
account_name sysname COLLATE database_default NOT NULL PRIMARY KEY,
type NVARCHAR(10) COLLATE database_default NOT NULL,
privilege NVARCHAR(10) COLLATE database_default NOT NULL,
mapped_login_name sysname COLLATE database_default NOT NULL,
permission_path sysname COLLATE database_default NULL
)
-- Call xp_logininfo to determine server access
INSERT INTO @xp_results
EXECUTE master.dbo.xp_logininfo @login_name
IF (SELECT COUNT(*) FROM @xp_results) > 0
BEGIN
SET @has_server_access = 1
SET @login_found = 1
END
SELECT @actual_login_name = mapped_login_name,
@is_sysadmin = CASE UPPER(privilege collate SQL_Latin1_General_CP1_CS_AS)
WHEN 'ADMIN' THEN 1
ELSE 0
END
FROM @xp_results
END
END
-- Only cache the NT logins to approximate the behavior of Sql Server and Windows (see bug 323287)
-- update the cache only if something is found
IF (UPPER(@actual_login_name collate SQL_Latin1_General_CP1_CS_AS) <> '(UNKNOWN)')
BEGIN
-- Procedure starts its own transaction.
BEGIN TRANSACTION;
-- Modify database.
-- use a try catch login to prevent any error when trying
-- to insert/update syscachedcredentials table
-- no need to fail since the job owner has been validated
BEGIN TRY
IF EXISTS (SELECT * FROM msdb.dbo.syscachedcredentials WITH (TABLOCKX) WHERE login_name = @login_name)
BEGIN
UPDATE msdb.dbo.syscachedcredentials
SET has_server_access = @has_server_access,
is_sysadmin_member = @is_sysadmin,
cachedate = GETDATE()
WHERE login_name = @login_name
END
ELSE
BEGIN
INSERT INTO msdb.dbo.syscachedcredentials(login_name, has_server_access, is_sysadmin_member)
VALUES(@login_name, @has_server_access, @is_sysadmin)
END
END TRY
BEGIN CATCH
-- If an error occurred we want to ignore it
END CATCH
-- The procedure must commit the transaction it started.
COMMIT TRANSACTION;
END
END
ELSE
BEGIN
-- Standard login
IF (EXISTS (SELECT *
FROM master.dbo.syslogins
WHERE (loginname = @login_name)))
BEGIN
SELECT @has_server_access = hasaccess,
@is_sysadmin = sysadmin,
@actual_login_name = loginname
FROM master.dbo.syslogins
WHERE (loginname = @login_name)
SET @login_found = 1
END
END
IF (@is_sysadmin_member IS NULL)
-- Return result row
SELECT has_server_access = @has_server_access,
is_sysadmin = @is_sysadmin,
actual_login_name = @actual_login_name,
login_found = @login_found
ELSE
-- output variable only
SELECT @is_sysadmin_member = @is_sysadmin
END
go
/**************************************************************/
/* SP_SQLAGENT_GET_PERF_COUNTERS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sqlagent_get_perf_counters...'
GO
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_sqlagent_get_perf_counters')
AND (type = 'P')))
DROP PROCEDURE sp_sqlagent_get_perf_counters
GO
CREATE PROCEDURE sp_sqlagent_get_perf_counters
@all_counters BIT = 0
AS
BEGIN
SET NOCOUNT ON
-- 32 bit fraction counter types
DECLARE @perfTypeRawFraction INT
DECLARE @perfTypeRawBase INT
-- A counter of type PERF_RAW_FRACTION, which is a 32-bit counter value.
SET @perfTypeRawFraction = 537003008 -- In hex, 0x20020400.
-- A count of type PERF_RAW_BASE, which is the 32-bit divisor used
-- when handling PERF_RAW_FRACTION types. This counter type should
-- not be displayed to the user since it is used for mathematical
-- operations.
SET @perfTypeRawBase = 1073939459 -- In hex, 0x40030403.
-- 64 bit fraction counter types
DECLARE @perfTypeLargeRawFraction INT
DECLARE @perfTypeLargeRawBase INT
-- A counter of type PERF_LARGE RAW_FRACTION, which is a 64-bit counter value.
SET @perfTypeLargeRawFraction = 537003264 -- In hex, 0x20020500.
-- A count of type PERF_LARGE_RAW_BASE, which is the 64-bit divisor used
-- when handling PERF_LARGE_RAW_FRACTION types. This counter type should
-- not be displayed to the user since it is used for mathematical
-- operations.
SET @perfTypeLargeRawBase = 1073939712 -- In hex, 0x40030500.
IF (@all_counters = 0)
BEGIN
SELECT spi1.object_name,
spi1.counter_name,
'instance_name' = CASE spi1.instance_name
WHEN N'' THEN NULL
ELSE spi1.instance_name
END,
'value' = CASE spi1.cntr_type
WHEN @perfTypeRawFraction -- 32 bit fraction
THEN CONVERT(FLOAT, spi1.cntr_value) / (SELECT CASE spi2.cntr_value
WHEN 0 THEN 1
ELSE spi2.cntr_value
END
FROM sysalerts_performance_counters_view spi2
WHERE (RTRIM(spi1.counter_name) + ' ' = SUBSTRING(spi2.counter_name, 1, PATINDEX('% base%', LOWER(spi2.counter_name))))
AND spi1.object_name = spi2.object_name
AND spi1.server_name = spi2.server_name
AND spi1.instance_name = spi2.instance_name
AND spi2.cntr_type = @perfTypeRawBase
)
WHEN @perfTypeLargeRawFraction -- 64 bit fraction
THEN CONVERT(FLOAT, spi1.cntr_value) / (SELECT CASE spi2.cntr_value
WHEN 0 THEN 1
ELSE spi2.cntr_value
END
FROM sysalerts_performance_counters_view spi2
WHERE (RTRIM(spi1.counter_name) + ' ' = SUBSTRING(spi2.counter_name, 1, PATINDEX('% base%', LOWER(spi2.counter_name))))
AND spi1.object_name = spi2.object_name
AND spi1.server_name = spi2.server_name
AND spi1.instance_name = spi2.instance_name
AND spi2.cntr_type = @perfTypeLargeRawBase
)
ELSE spi1.cntr_value
END,
'type' = spi1.cntr_type,
spi1.server_name
FROM sysalerts_performance_counters_view spi1,
(
SELECT DISTINCT
SUBSTRING(performance_condition,
PATINDEX('%:%', performance_condition) + 1,
CHARINDEX('|', performance_condition,
PATINDEX('%_|_%', performance_condition) + 2)-(PATINDEX('%:%', performance_condition) + 1
)
)
AS performance_condition_s
FROM msdb.dbo.sysalerts
WHERE performance_condition IS NOT NULL
AND ISNULL(event_id, 0) <> 8 -- exclude WMI events that reuse performance_condition field
AND enabled = 1
) tmp -- We want to select only those counters that have an enabled performance sysalert
WHERE spi1.cntr_type <> @perfTypeRawBase -- ignore 32-bit denominator counter type
AND spi1.cntr_type <> @perfTypeLargeRawBase -- ignore 64-bit denominator counter type
AND tmp.performance_condition_s = (spi1.object_name + '|' + spi1.counter_name)
OPTION (HASH JOIN, LOOP JOIN) -- Avoid merge join when small number of alerts are defined
END
ELSE
BEGIN
SELECT spi1.object_name,
spi1.counter_name,
'instance_name' = CASE spi1.instance_name
WHEN N'' THEN NULL
ELSE spi1.instance_name
END,
'value' = CASE spi1.cntr_type
WHEN @perfTypeRawFraction -- 32 bit fraction
THEN CONVERT(FLOAT, spi1.cntr_value) / (SELECT CASE spi2.cntr_value
WHEN 0 THEN 1
ELSE spi2.cntr_value
END
FROM sysalerts_performance_counters_view spi2
WHERE (RTRIM(spi1.counter_name) + ' ' = SUBSTRING(spi2.counter_name, 1, PATINDEX('% base%', LOWER(spi2.counter_name))))
AND spi1.object_name = spi2.object_name
AND spi1.server_name = spi2.server_name
AND spi1.instance_name = spi2.instance_name
AND spi2.cntr_type = @perfTypeRawBase
)
WHEN @perfTypeLargeRawFraction -- 64 bit fraction
THEN CONVERT(FLOAT, spi1.cntr_value) / (SELECT CASE spi2.cntr_value
WHEN 0 THEN 1
ELSE spi2.cntr_value
END
FROM sysalerts_performance_counters_view spi2
WHERE (RTRIM(spi1.counter_name) + ' ' = SUBSTRING(spi2.counter_name, 1, PATINDEX('% base%', LOWER(spi2.counter_name))))
AND spi1.object_name = spi2.object_name
AND spi1.server_name = spi2.server_name
AND spi1.instance_name = spi2.instance_name
AND spi2.cntr_type = @perfTypeLargeRawBase
)
ELSE spi1.cntr_value
END,
'type' = spi1.cntr_type,
spi1.server_name
FROM sysalerts_performance_counters_view spi1
WHERE spi1.cntr_type <> @perfTypeRawBase -- ignore 32-bit denominator counter type
AND spi1.cntr_type <> @perfTypeLargeRawBase -- ignore 64-bit denominator counter type
END
END
GO
/**************************************************************/
/* SP_SQLAGENT_NOTIFY */
/* */
/* NOTE: We define this procedure here instead of in the */
/* 'Support procedures' section because of the many */
/* other procedures that reference it. */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sqlagent_notify...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_sqlagent_notify')
AND (type = 'P')))
DROP PROCEDURE sp_sqlagent_notify
go
CREATE PROCEDURE sp_sqlagent_notify
@op_type NCHAR(1), -- One of: J (Job action [refresh or start/stop]),
-- S (Schedule action [refresh only])
-- A (Alert action [refresh only]),
-- G (Re-cache all registry settings),
-- D (Dump job [or job schedule] cache to errorlog)
-- P (Force an immediate poll of the MSX)
-- L (Cycle log file)
-- T (Test WMI parameters (namespace and query))
-- M (DatabaseMail action [ refresh profile associated with sql agent)
@job_id UNIQUEIDENTIFIER = NULL, -- JobID (for OpTypes 'J', 'S' and 'D')
@schedule_id INT = NULL, -- ScheduleID (for OpType 'S')
@alert_id INT = NULL, -- AlertID (for OpType 'A')
@action_type NCHAR(1) = NULL, -- For 'J' one of: R (Run - no service check),
-- S (Start - with service check),
-- I (Insert),
-- U (Update),
-- D (Delete),
-- C (Stop [Cancel])
-- For 'S' or 'A' one of: I (Insert),
-- U (Update),
-- D (Delete)
@error_flag INT = 1, -- Set to 0 to suppress the error from xp_sqlagent_notify if SQLServer agent is not running
@wmi_namespace nvarchar(128) = NULL,
@wmi_query nvarchar(512) = NULL
AS
BEGIN
DECLARE @retval INT
DECLARE @id_as_char VARCHAR(10)
DECLARE @job_id_as_char VARCHAR(36)
DECLARE @nt_user_name NVARCHAR(100)
SET NOCOUNT ON
SELECT @retval = 0 -- Success
-- Make sure that we're dealing only with uppercase characters
SELECT @op_type = UPPER(@op_type collate SQL_Latin1_General_CP1_CS_AS)
SELECT @action_type = UPPER(@action_type collate SQL_Latin1_General_CP1_CS_AS)
-- Verify operation code
IF (CHARINDEX(@op_type, N'JSAGDPLTM') = 0)
BEGIN
RAISERROR(14266, -1, -1, '@op_type', 'J, S, A, G, D, P, L, T, M')
RETURN(1) -- Failure
END
-- Check the job id for those who use it
IF (CHARINDEX(@op_type, N'JSD') <> 0)
BEGIN
IF (NOT ((@op_type = N'D' OR @op_type = N'S') AND (@job_id IS NULL))) -- For 'D' and 'S' job_id is optional
BEGIN
IF ((@job_id IS NULL) OR
((@action_type <> N'D') AND NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobs_view
WHERE (job_id = @job_id))))
BEGIN
SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)
RETURN(1) -- Failure
END
END
END
-- Verify 'job' action parameters
IF (@op_type = N'J')
BEGIN
SELECT @alert_id = 0
IF (@schedule_id IS NULL) SELECT @schedule_id = 0
-- The schedule_id (if specified) is the start step
IF ((CHARINDEX(@action_type, N'RS') <> 0) AND (@schedule_id <> 0))
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND (step_id = @schedule_id)))
BEGIN
SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @schedule_id), '(null)')
RAISERROR(14262, -1, -1, '@schedule_id', @id_as_char)
RETURN(1) -- Failure
END
END
ELSE
SELECT @schedule_id = 0
IF (CHARINDEX(@action_type, N'RSIUDC') = 0)
BEGIN
RAISERROR(14266, -1, -1, '@action_type', 'R, S, I, U, D, C')
RETURN(1) -- Failure
END
END
-- Verify 'schedule' action parameters
IF (@op_type = N'S')
BEGIN
SELECT @alert_id = 0
IF (CHARINDEX(@action_type, N'IUD') = 0)
BEGIN
RAISERROR(14266, -1, -1, '@action_type', 'I, U, D')
RETURN(1) -- Failure
END
IF ((@schedule_id IS NULL) OR
((@action_type <> N'D') AND NOT EXISTS (SELECT *
FROM msdb.dbo.sysschedules
WHERE (schedule_id = @schedule_id))))
BEGIN
SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @schedule_id), '(null)')
RAISERROR(14262, -1, -1, '@schedule_id', @id_as_char)
RETURN(1) -- Failure
END
END
-- Verify 'alert' action parameters
IF (@op_type = N'A')
BEGIN
SELECT @job_id = 0x00
SELECT @schedule_id = 0
IF (CHARINDEX(@action_type, N'IUD') = 0)
BEGIN
RAISERROR(14266, -1, -1, '@action_type', 'I, U, D')
RETURN(1) -- Failure
END
IF ((@alert_id IS NULL) OR
((@action_type <> N'D') AND NOT EXISTS (SELECT *
FROM msdb.dbo.sysalerts
WHERE (id = @alert_id))))
BEGIN
SELECT @id_as_char = ISNULL(CONVERT(VARCHAR, @alert_id), '(null)')
RAISERROR(14262, -1, -1, '@alert_id', @id_as_char)
RETURN(1) -- Failure
END
END
-- Verify 'registry', 'job dump' and 'force MSX poll' , 'cycle log', dbmail profile refresh action parameters
IF (CHARINDEX(@op_type, N'GDPLM') <> 0)
BEGIN
IF (@op_type <> N'D')
SELECT @job_id = 0x00
SELECT @alert_id = 0
SELECT @schedule_id = 0
SELECT @action_type = NULL
END
-- Parameters are valid, so now check execution permissions...
-- For anything except a job (or schedule) action the caller must be SysAdmin, DBO, or DB_Owner
IF (@op_type NOT IN (N'J', N'S'))
BEGIN
IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR
(ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR
(UPPER(USER_NAME() collate SQL_Latin1_General_CP1_CS_AS) = N'DBO'))
BEGIN
RAISERROR(14260, -1, -1)
RETURN(1) -- Failure
END
END
-- For a Job Action the caller must be SysAdmin, DBO, DB_Owner, or the job owner
IF (@op_type = N'J')
BEGIN
IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR
(ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR
(UPPER(USER_NAME() collate SQL_Latin1_General_CP1_CS_AS) = N'DBO') OR
(EXISTS (SELECT *
FROM msdb.dbo.sysjobs_view
WHERE (job_id = @job_id))))
BEGIN
RAISERROR(14252, -1, -1)
RETURN(1) -- Failure
END
END
--verify WMI parameters
IF (@op_type = N'T')
BEGIN
SELECT @wmi_namespace = LTRIM(RTRIM(@wmi_namespace))
SELECT @wmi_query = LTRIM(RTRIM(@wmi_query))
IF (@wmi_namespace IS NULL) or (@wmi_query IS NULL)
BEGIN
RAISERROR(14508, 16, 1)
RETURN(1) -- Failure
END
END
-- Ok, let's do it...
SELECT @nt_user_name = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))
EXECUTE @retval = master.dbo.xp_sqlagent_notify @op_type, @job_id, @schedule_id, @alert_id, @action_type, @nt_user_name, @error_flag, @@trancount, @wmi_namespace, @wmi_query
RETURN(@retval)
END
go
/**************************************************************/
/* SP_IS_SQLAGENT_STARTING */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_is_sqlagent_starting...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_is_sqlagent_starting')
AND (type = 'P')))
DROP PROCEDURE sp_is_sqlagent_starting
go
CREATE PROCEDURE sp_is_sqlagent_starting
AS
BEGIN
DECLARE @retval INT
SELECT @retval = 0
EXECUTE master.dbo.xp_sqlagent_is_starting @retval OUTPUT
IF (@retval = 1)
RAISERROR(14258, -1, -1)
RETURN(@retval)
END
go
/**************************************************************/
/* SP_VERIFY_JOB_IDENTIFIERS */
/* */
/* NOTE: We define this procedure here instead of in the */
/* 'Support procedures' section because of the many */
/* other procedures that reference it. */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_job_identifiers...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_job_identifiers')
AND (type = 'P')))
DROP PROCEDURE sp_verify_job_identifiers
go
CREATE PROCEDURE sp_verify_job_identifiers
@name_of_name_parameter VARCHAR(60), -- Eg. '@job_name'
@name_of_id_parameter VARCHAR(60), -- Eg. '@job_id'
@job_name sysname OUTPUT, -- Eg. 'My Job'
@job_id UNIQUEIDENTIFIER OUTPUT,
@sqlagent_starting_test VARCHAR(7) = 'TEST', -- By default we DO want to test if SQLServerAgent is running (caller should specify 'NO_TEST' if not desired)
@owner_sid VARBINARY(85) = NULL OUTPUT
AS
BEGIN
DECLARE @retval INT
DECLARE @job_id_as_char VARCHAR(36)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name_of_name_parameter = LTRIM(RTRIM(@name_of_name_parameter))
SELECT @name_of_id_parameter = LTRIM(RTRIM(@name_of_id_parameter))
SELECT @job_name = LTRIM(RTRIM(@job_name))
IF (@job_name = N'') SELECT @job_name = NULL
IF ((@job_name IS NULL) AND (@job_id IS NULL)) OR
((@job_name IS NOT NULL) AND (@job_id IS NOT NULL))
BEGIN
RAISERROR(14294, -1, -1, @name_of_id_parameter, @name_of_name_parameter)
RETURN(1) -- Failure
END
-- Check job id
IF (@job_id IS NOT NULL)
BEGIN
SELECT @job_name = name,
@owner_sid = owner_sid
FROM msdb.dbo.sysjobs_view
WHERE (job_id = @job_id)
-- the view would take care of all the permissions issues.
IF (@job_name IS NULL)
BEGIN
SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)
RETURN(1) -- Failure
END
END
ELSE
-- Check job name
IF (@job_name IS NOT NULL)
BEGIN
-- Check if the job name is ambiguous
IF ((SELECT COUNT(*)
FROM msdb.dbo.sysjobs_view
WHERE (name = @job_name)) > 1)
BEGIN
RAISERROR(14293, -1, -1, @job_name, @name_of_id_parameter, @name_of_name_parameter)
RETURN(1) -- Failure
END
-- The name is not ambiguous, so get the corresponding job_id (if the job exists)
SELECT @job_id = job_id,
@owner_sid = owner_sid
FROM msdb.dbo.sysjobs_view
WHERE (name = @job_name)
-- the view would take care of all the permissions issues.
IF (@job_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@job_name', @job_name)
RETURN(1) -- Failure
END
END
IF (@sqlagent_starting_test = 'TEST')
BEGIN
-- Finally, check if SQLServerAgent is in the process of starting and if so prevent the
-- calling SP from running
EXECUTE @retval = msdb.dbo.sp_is_sqlagent_starting
IF (@retval <> 0)
RETURN(1) -- Failure
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_VERIFY_SCHEDULE_IDENTIFIERS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_schedule_identifiers...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_schedule_identifiers')
AND (type = 'P')))
DROP PROCEDURE sp_verify_schedule_identifiers
go
CREATE PROCEDURE sp_verify_schedule_identifiers
@name_of_name_parameter VARCHAR(60), -- Eg. '@schedule_name'
@name_of_id_parameter VARCHAR(60), -- Eg. '@schedule_id'
@schedule_name sysname OUTPUT,
@schedule_id INT OUTPUT,
@owner_sid VARBINARY(85) OUTPUT,
@orig_server_id INT OUTPUT,
@job_id_filter UNIQUEIDENTIFIER = NULL
AS
BEGIN
DECLARE @retval INT
DECLARE @schedule_id_as_char VARCHAR(36)
DECLARE @sch_name_count INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name_of_name_parameter = LTRIM(RTRIM(@name_of_name_parameter))
SELECT @name_of_id_parameter = LTRIM(RTRIM(@name_of_id_parameter))
SELECT @schedule_name = LTRIM(RTRIM(@schedule_name))
SELECT @sch_name_count = 0
IF (@schedule_name = N'') SELECT @schedule_name = NULL
IF ((@schedule_name IS NULL) AND (@schedule_id IS NULL)) OR
((@schedule_name IS NOT NULL) AND (@schedule_id IS NOT NULL))
BEGIN
RAISERROR(14373, -1, -1, @name_of_id_parameter, @name_of_name_parameter)
RETURN(1) -- Failure
END
-- Check schedule id
IF (@schedule_id IS NOT NULL)
BEGIN
-- if Agent is calling look in all schedules not just the local server schedules
if(PROGRAM_NAME() LIKE N'SQLAgent%')
BEGIN
-- Look at all schedules
SELECT @schedule_name = name,
@owner_sid = owner_sid,
@orig_server_id = originating_server_id
FROM msdb.dbo.sysschedules
WHERE (schedule_id = @schedule_id)
END
ELSE
BEGIN
--Look at local schedules only
SELECT @schedule_name = name,
@owner_sid = owner_sid,
@orig_server_id = originating_server_id
FROM msdb.dbo.sysschedules_localserver_view
WHERE (schedule_id = @schedule_id)
END
IF (@schedule_name IS NULL)
BEGIN
--If the schedule is from an MSX and a sysadmin is calling report a specific 'MSX' message
IF(PROGRAM_NAME() NOT LIKE N'SQLAgent%' AND
ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1 AND
EXISTS(SELECT *
FROM msdb.dbo.sysschedules as sched
JOIN msdb.dbo.sysoriginatingservers_view as svr
ON sched.originating_server_id = svr.originating_server_id
WHERE (schedule_id = @schedule_id) AND
(svr.master_server = 1)))
BEGIN
RAISERROR(14274, -1, -1)
END
ELSE
BEGIN
SELECT @schedule_id_as_char = CONVERT(VARCHAR(36), @schedule_id)
RAISERROR(14262, -1, -1, '@schedule_id', @schedule_id_as_char)
END
RETURN(1) -- Failure
END
END
ELSE
-- Check job name
IF (@schedule_name IS NOT NULL)
BEGIN
-- if a job_id is supplied use it as a filter. This helps with V8 legacy support
IF(@job_id_filter IS NOT NULL)
BEGIN
-- Check if the job name is ambiguous and also get the schedule_id optimistically.
-- If the name is not ambiguous this gets the corresponding schedule_id (if the schedule exists)
SELECT @sch_name_count = COUNT(*),
@schedule_id = MIN(s.schedule_id),
@owner_sid = MIN(owner_sid),
@orig_server_id = MIN(originating_server_id)
FROM msdb.dbo.sysschedules_localserver_view as s
JOIN msdb.dbo.sysjobschedules as js
ON s.schedule_id = js.schedule_id
WHERE (name = @schedule_name) AND
(js.job_id = @job_id_filter)
END
ELSE
BEGIN
-- Check if the job name is ambiguous from the count(*) result
-- If the name is not ambiguous it is safe use the fields returned by the MIN() function
SELECT @sch_name_count = COUNT(*),
@schedule_id = MIN(schedule_id),
@owner_sid = MIN(owner_sid),
@orig_server_id = MIN(originating_server_id)
FROM msdb.dbo.sysschedules_localserver_view
WHERE (name = @schedule_name)
END
IF(@sch_name_count > 1)
BEGIN
-- ambiguous, user needs to use a schedule_id instead of a schedule_name
RAISERROR(14371, -1, -1, @schedule_name, @name_of_id_parameter, @name_of_name_parameter)
RETURN(1) -- Failure
END
--schedule_id isn't visible to this user or doesn't exist
IF (@schedule_id IS NULL)
BEGIN
--If the schedule is from an MSX and a sysadmin is calling report a specific 'MSX' message
IF(PROGRAM_NAME() NOT LIKE N'SQLAgent%' AND
ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1 AND
EXISTS(SELECT *
FROM msdb.dbo.sysschedules as sched
JOIN msdb.dbo.sysoriginatingservers_view as svr
ON sched.originating_server_id = svr.originating_server_id
JOIN msdb.dbo.sysjobschedules as js
ON sched.schedule_id = js.schedule_id
WHERE (svr.master_server = 1) AND
(name = @schedule_name) AND
((@job_id_filter IS NULL) OR (js.job_id = @job_id_filter))))
BEGIN
RAISERROR(14274, -1, -1)
END
ELSE
BEGIN
--If not a MSX schedule raise local error
RAISERROR(14262, -1, -1, '@schedule_name', @schedule_name)
END
RETURN(1) -- Failure
END
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_VERIFY_JOBPROC_CALLER */
/* */
/* NOTE: We define this procedure here instead of in the */
/* 'Support procedures' section because of the many */
/* other procedures that reference it. */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_jobproc_caller...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_jobproc_caller')
AND (type = 'P')))
DROP PROCEDURE sp_verify_jobproc_caller
go
CREATE PROCEDURE sp_verify_jobproc_caller
@job_id UNIQUEIDENTIFIER,
@program_name sysname
AS
BEGIN
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @program_name = LTRIM(RTRIM(@program_name))
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobs_view
WHERE (job_id = @job_id)
AND (master_server = 1) )) -- master_server = 1 filters on MSX jobs in this TSX server
AND (PROGRAM_NAME() NOT LIKE @program_name)
BEGIN
RAISERROR(14274, -1, -1)
RETURN(1) -- Failure
END
RETURN(0)
END
go
/**************************************************************/
/* SP_DOWNLOADED_ROW_LIMITER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_downloaded_row_limiter...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_downloaded_row_limiter')
AND (type = 'P')))
DROP PROCEDURE dbo.sp_downloaded_row_limiter
go
CREATE PROCEDURE sp_downloaded_row_limiter
@server_name sysname -- Target server name
AS
BEGIN
-- This trigger controls how many downloaded (status = 1) sysdownloadlist rows exist
-- for any given server. It does NOT control the absolute number of rows in the table.
DECLARE @current_rows_per_server INT
DECLARE @max_rows_per_server INT -- This value comes from the resgistry (DownloadedMaxRows)
DECLARE @rows_to_delete INT
DECLARE @quoted_server_name NVARCHAR(514) -- enough room to accomodate the quoted name
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @server_name = LTRIM(RTRIM(@server_name))
-- Check the server name (if it's bad we fail silently)
IF (@server_name IS NULL) OR
(NOT EXISTS (SELECT *
FROM msdb.dbo.sysdownloadlist
WHERE (target_server = @server_name)))
RETURN(1) -- Failure
SELECT @max_rows_per_server = 0
-- Get the max-rows-per-server from the registry
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'DownloadedMaxRows',
@max_rows_per_server OUTPUT,
N'no_output'
-- Check if we are limiting sysdownloadlist rows
IF (ISNULL(@max_rows_per_server, -1) = -1)
RETURN
-- Check that max_rows_per_server is >= 0
IF (@max_rows_per_server < -1)
BEGIN
-- It isn't, so default to 100 rows
SELECT @max_rows_per_server = 100
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'DownloadedMaxRows',
N'REG_DWORD',
@max_rows_per_server
END
-- Get the number of downloaded rows in sysdownloadlist for the target server in question
-- NOTE: Determining this [quickly] requires a [non-clustered] index on target_server
SELECT @current_rows_per_server = COUNT(*)
FROM msdb.dbo.sysdownloadlist
WHERE (target_server = @server_name)
AND (status = 1)
-- Delete the oldest downloaded row(s) for the target server in question if the new row has
-- pushed us over the per-server row limit
SELECT @rows_to_delete = @current_rows_per_server - @max_rows_per_server
IF (@rows_to_delete > 0)
BEGIN
WITH RowsToDelete AS (
SELECT TOP (@rows_to_delete) *
FROM msdb.dbo.sysdownloadlist
WHERE (target_server = @server_name)
AND (status = 1)
ORDER BY instance_id
)
DELETE FROM RowsToDelete;
END
END
go
/**************************************************************/
/* SP_POST_MSX_OPERATION */
/* */
/* NOTE: We define this procedure here instead of in the */
/* 'Support procedures' section because of the many */
/* other procedures that reference it. */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_post_msx_operation...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_post_msx_operation')
AND (type = 'P')))
DROP PROCEDURE sp_post_msx_operation
go
CREATE PROCEDURE sp_post_msx_operation
@operation VARCHAR(64),
@object_type VARCHAR(64) = 'JOB',-- Can be JOB, SERVER or SCHEDULE
@job_id UNIQUEIDENTIFIER = NULL, -- NOTE: 0x00 means 'ALL' jobs
@specific_target_server sysname = NULL,
@value INT = NULL, -- For polling interval value
@schedule_uid UNIQUEIDENTIFIER = NULL -- schedule_uid if the @object_type = 'SCHEDULE'
AS
BEGIN
DECLARE @operation_code INT
DECLARE @specific_target_server_id INT
DECLARE @instructions_posted INT
DECLARE @job_id_as_char VARCHAR(36)
DECLARE @schedule_uid_as_char VARCHAR(36)
DECLARE @msx_time_zone_adjustment INT
DECLARE @local_machine_name sysname
DECLARE @retval INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @operation = LTRIM(RTRIM(@operation))
SELECT @object_type = LTRIM(RTRIM(@object_type))
SELECT @specific_target_server = LTRIM(RTRIM(@specific_target_server))
-- Turn [nullable] empty string parameters into NULLs
IF (@specific_target_server = N'') SELECT @specific_target_server = NULL
-- Only a sysadmin can do this, but fail silently for a non-sysadmin
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
RETURN(0) -- Success (or more accurately a no-op)
-- Check operation
SELECT @operation = UPPER(@operation collate SQL_Latin1_General_CP1_CS_AS)
SELECT @operation_code = CASE @operation
WHEN 'INSERT' THEN 1
WHEN 'UPDATE' THEN 2
WHEN 'DELETE' THEN 3
WHEN 'START' THEN 4
WHEN 'STOP' THEN 5
WHEN 'RE-ENLIST' THEN 6
WHEN 'DEFECT' THEN 7
WHEN 'SYNC-TIME' THEN 8
WHEN 'SET-POLL' THEN 9
ELSE 0
END
IF (@operation_code = 0)
BEGIN
RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP, RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')
RETURN(1) -- Failure
END
-- Check object type (in 9.0 only 'JOB', 'SERVER' or 'SCHEDULE'are valid)
IF ((@object_type <> 'JOB') AND (@object_type <> 'SERVER') AND (@object_type <> 'SCHEDULE'))
BEGIN
RAISERROR(14266, -1, -1, '@object_type', 'JOB, SERVER, SCHEDULE')
RETURN(1) -- Failure
END
-- Check that for a object type of JOB a job_id has been supplied
IF ((@object_type = 'JOB') AND (@job_id IS NULL))
BEGIN
RAISERROR(14233, -1, -1)
RETURN(1) -- Failure
END
-- Check that for a object type of JOB a job_id has been supplied
IF ((@object_type = 'SCHEDULE') AND (@schedule_uid IS NULL))
BEGIN
RAISERROR(14365, -1, -1)
RETURN(1) -- Failure
END
-- Check polling interval value
IF (@operation_code = 9) AND ((ISNULL(@value, 0) < 10) OR (ISNULL(@value, 0) > 28800))
BEGIN
RAISERROR(14266, -1, -1, '@value', '10..28800')
RETURN(1) -- Failure
END
-- Check specific target server
IF (@specific_target_server IS NOT NULL)
BEGIN
SELECT @specific_target_server = UPPER(@specific_target_server)
-- Check if the local server is being targeted
IF (@specific_target_server = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))
BEGIN
RETURN(0)
END
ELSE
BEGIN
SELECT @specific_target_server_id = server_id
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = @specific_target_server)
IF (@specific_target_server_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@specific_target_server', @specific_target_server)
RETURN(1) -- Failure
END
END
END
-- Check that this server is an MSX server
IF ((SELECT COUNT(*)
FROM msdb.dbo.systargetservers) = 0)
BEGIN
RETURN(0)
END
-- Get local machine name
EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
IF (@retval <> 0) OR (@local_machine_name IS NULL)
BEGIN
RAISERROR(14225, -1, -1)
RETURN(1)
END
-- Job-specific processing...
IF (@object_type = 'JOB')
BEGIN
-- Validate the job (if supplied)
IF (@job_id <> CONVERT(UNIQUEIDENTIFIER, 0x00))
BEGIN
SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
-- Check if the job exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobs_view
WHERE (job_id = @job_id)))
BEGIN
RAISERROR(14262, -1, -1, '@job_id', @job_id_as_char)
RETURN(1) -- Failure
END
-- If this is a local job then there's nothing for us to do
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0))) -- 0 means local server
OR (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)))
BEGIN
RETURN(0)
END
END
-- Generate the sysdownloadlist row(s)...
IF (@operation_code = 1) OR -- Insert
(@operation_code = 2) OR -- Update
(@operation_code = 3) OR -- Delete
(@operation_code = 4) OR -- Start
(@operation_code = 5) -- Stop
BEGIN
IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) -- IE. 'ALL'
BEGIN
-- All jobs
-- Handle DELETE as a special case (rather than posting 1 instruction per job we just
-- post a single instruction that means 'delete all jobs from the MSX')
IF (@operation_code = 3)
BEGIN
INSERT INTO msdb.dbo.sysdownloadlist
(source_server,
operation_code,
object_type,
object_id,
target_server)
SELECT @local_machine_name,
@operation_code,
1, -- 1 means 'JOB'
CONVERT(UNIQUEIDENTIFIER, 0x00),
sts.server_name
FROM systargetservers sts
WHERE ((@specific_target_server_id IS NULL) OR (sts.server_id = @specific_target_server_id))
AND ((SELECT COUNT(*)
FROM msdb.dbo.sysjobservers
WHERE (server_id = sts.server_id)) > 0)
SELECT @instructions_posted = @@rowcount
END
ELSE
BEGIN
INSERT INTO msdb.dbo.sysdownloadlist
(source_server,
operation_code,
object_type,
object_id,
target_server)
SELECT @local_machine_name,
@operation_code,
1, -- 1 means 'JOB'
sjv.job_id,
sts.server_name
FROM sysjobs_view sjv,
sysjobservers sjs,
systargetservers sts
WHERE (sjv.job_id = sjs.job_id)
AND (sjs.server_id = sts.server_id)
AND (sjs.server_id <> 0) -- We want to exclude local jobs
AND ((@specific_target_server_id IS NULL) OR (sjs.server_id = @specific_target_server_id))
SELECT @instructions_posted = @@rowcount
END
END
ELSE
BEGIN
-- Specific job (ie. @job_id is not 0x00)
INSERT INTO msdb.dbo.sysdownloadlist
(source_server,
operation_code,
object_type,
object_id,
target_server,
deleted_object_name)
SELECT @local_machine_name,
@operation_code,
1, -- 1 means 'JOB'
sjv.job_id,
sts.server_name,
CASE @operation_code WHEN 3 -- Delete
THEN sjv.name
ELSE NULL
END
FROM sysjobs_view sjv,
sysjobservers sjs,
systargetservers sts
WHERE (sjv.job_id = @job_id)
AND (sjv.job_id = sjs.job_id)
AND (sjs.server_id = sts.server_id)
AND (sjs.server_id <> 0) -- We want to exclude local jobs
AND ((@specific_target_server_id IS NULL) OR (sjs.server_id = @specific_target_server_id))
SELECT @instructions_posted = @@rowcount
END
END
ELSE
BEGIN
RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP')
RETURN(1) -- Failure
END
END
-- SCHEDULE specific processing for INSERT, UPDATE or DELETE schedule operations
-- All msx jobs that use the specified @schedule_uid will be notified with an Insert operation.
-- This will cause agent to reload all schedules for each job.
-- This is compatible with the legacy shiloh servers that don't know about reusable schedules
IF (@object_type = 'SCHEDULE')
BEGIN
-- Validate the schedule
-- Check if the schedule exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysschedules_localserver_view
WHERE (schedule_uid = @schedule_uid)))
BEGIN
SELECT @schedule_uid_as_char = CONVERT(VARCHAR(36), @schedule_uid)
RAISERROR(14262, -1, -1, '@schedule_uid', @schedule_uid_as_char)
RETURN(1) -- Failure
END
-- If this schedule is only used locally (no target servers) then there's nothing to do
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysschedules s,
msdb.dbo.sysjobschedules js,
msdb.dbo.sysjobs_view sjv,
msdb.dbo.sysjobservers sjs,
msdb.dbo.systargetservers sts
WHERE (s.schedule_uid = @schedule_uid)
AND (s.schedule_id = js.schedule_id)
AND (sjv.job_id = js.job_id)
AND (sjv.job_id = sjs.job_id)
AND (sjs.server_id = sts.server_id)
AND (sjs.server_id <> 0)))
BEGIN
RETURN(0)
END
-- Generate the sysdownloadlist row(s)...
IF (@operation_code = 1) OR -- Insert
(@operation_code = 2) OR -- Update
(@operation_code = 3) -- Delete
BEGIN
-- Insert specific schedule into sysdownloadlist
-- We need to create a sysdownloadlist JOB INSERT record for each job that runs the schedule
INSERT INTO msdb.dbo.sysdownloadlist
(source_server,
operation_code,
object_type,
object_id,
target_server)
SELECT @local_machine_name,
1, -- 1 means 'Insert'
1, -- 1 means 'JOB'
sjv.job_id,
sts.server_name
FROM msdb.dbo.sysschedules s,
msdb.dbo.sysjobschedules js,
msdb.dbo.sysjobs_view sjv,
msdb.dbo.sysjobservers sjs,
systargetservers sts
WHERE (s.schedule_id = js.schedule_id)
AND (js.job_id = sjv.job_id)
AND (sjv.job_id = sjs.job_id)
AND (sjs.server_id = sts.server_id)
AND (s.schedule_uid = @schedule_uid)
AND (sjs.server_id <> 0) -- We want to exclude local jobs
AND ((@specific_target_server_id IS NULL) OR (sjs.server_id = @specific_target_server_id))
SELECT @instructions_posted = @@rowcount
END
ELSE
BEGIN
RAISERROR(14266, -1, -1, '@operation_code', 'UPDATE, DELETE')
RETURN(1) -- Failure
END
END
-- Server-specific processing...
IF (@object_type = 'SERVER')
BEGIN
-- Generate the sysdownloadlist row(s)...
IF (@operation_code = 6) OR -- ReEnlist
(@operation_code = 7) OR -- Defect
(@operation_code = 8) OR -- Synchronize time (with MSX)
(@operation_code = 9) -- Set MSX polling interval (in seconds)
BEGIN
IF (@operation_code = 8)
BEGIN
EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
N'SYSTEM\CurrentControlSet\Control\TimeZoneInformation',
N'Bias',
@msx_time_zone_adjustment OUTPUT,
N'no_output'
SELECT @msx_time_zone_adjustment = -ISNULL(@msx_time_zone_adjustment, 0)
END
INSERT INTO msdb.dbo.sysdownloadlist
(source_server,
operation_code,
object_type,
object_id,
target_server)
SELECT @local_machine_name,
@operation_code,
2, -- 2 means 'SERVER'
CASE @operation_code
WHEN 8 THEN CONVERT(UNIQUEIDENTIFIER, CONVERT(BINARY(16), -(@msx_time_zone_adjustment - sts.time_zone_adjustment)))
WHEN 9 THEN CONVERT(UNIQUEIDENTIFIER, CONVERT(BINARY(16), @value))
ELSE CONVERT(UNIQUEIDENTIFIER, 0x00)
END,
sts.server_name
FROM systargetservers sts
WHERE ((@specific_target_server_id IS NULL) OR (sts.server_id = @specific_target_server_id))
SELECT @instructions_posted = @@rowcount
END
ELSE
BEGIN
RAISERROR(14266, -1, -1, '@operation_code', 'RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')
RETURN(1) -- Failure
END
END
-- Report number of rows inserted
IF (@object_type = 'JOB') AND
(@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND
(@instructions_posted = 0) AND
(@specific_target_server_id IS NOT NULL)
RAISERROR(14231, 0, 1, '@specific_target_server', @specific_target_server)
ELSE
RAISERROR(14230, 0, 1, @instructions_posted, @operation)
-- Delete any [downloaded] instructions that are over the registry-defined limit
IF (@specific_target_server IS NOT NULL)
EXECUTE msdb.dbo.sp_downloaded_row_limiter @specific_target_server
RETURN(0) -- 0 means success
END
go
/**************************************************************/
/* SP_VERIFY_PERFORMANCE_CONDITION */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_performance_condition...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_performance_condition')
AND (type = 'P')))
DROP PROCEDURE sp_verify_performance_condition
go
CREATE PROCEDURE sp_verify_performance_condition
@performance_condition NVARCHAR(512)
AS
BEGIN
DECLARE @delimiter_count INT
DECLARE @temp_str NVARCHAR(512)
DECLARE @object_name sysname
DECLARE @counter_name sysname
DECLARE @instance_name sysname
DECLARE @pos INT
SET NOCOUNT ON
-- The performance condition must have the format 'object|counter|instance|comparator|value'
-- NOTE: 'instance' may be empty.
IF (PATINDEX(N'%_|%_|%|[><=]|[0-9]%', @performance_condition) = 0)
BEGIN
RAISERROR(14507, 16, 1)
RETURN(1) -- Failure
END
-- Parse the performance_condition
SELECT @delimiter_count = 0
--Ex: "SqlServer:General Statistics|User Connections||>|5" => "General Statistics|User Connections||>|5"
SELECT @temp_str = SUBSTRING(@performance_condition,
PATINDEX('%:%', @performance_condition)+1,
DATALENGTH(@performance_condition) - (PATINDEX('%:%', @performance_condition)+1) )
SELECT @pos = CHARINDEX(N'|', @temp_str)
WHILE (@pos <> 0)
BEGIN
SELECT @delimiter_count = @delimiter_count + 1
IF (@delimiter_count = 1) SELECT @object_name = SUBSTRING(@temp_str, 1, @pos - 1)
IF (@delimiter_count = 2) SELECT @counter_name = SUBSTRING(@temp_str, 1, @pos - 1)
IF (@delimiter_count = 3) SELECT @instance_name = SUBSTRING(@temp_str, 1, @pos - 1)
SELECT @temp_str = SUBSTRING(@temp_str, @pos + 1, (DATALENGTH(@temp_str) / 2) - @pos)
SELECT @pos = CHARINDEX(N'|', @temp_str)
END
IF (@delimiter_count <> 4)
BEGIN
RAISERROR(14507, 16, 1)
RETURN(1) -- Failure
END
-- Check the object_name
IF (NOT EXISTS (SELECT object_name
FROM dbo.sysalerts_performance_counters_view
WHERE (object_name = @object_name)))
BEGIN
RAISERROR(14262, 16, 1, 'object_name', @object_name)
RETURN(1) -- Failure
END
-- Check the counter_name
IF (NOT EXISTS (SELECT counter_name
FROM dbo.sysalerts_performance_counters_view
WHERE (object_name = @object_name)
AND (counter_name = @counter_name)))
BEGIN
RAISERROR(14262, 16, 1, 'counter_name', @counter_name)
RETURN(1) -- Failure
END
-- Check the instance_name
IF (@instance_name IS NOT NULL)
BEGIN
IF (NOT EXISTS (SELECT instance_name
FROM dbo.sysalerts_performance_counters_view
WHERE (object_name = @object_name)
AND (counter_name = @counter_name)
AND (instance_name = @instance_name)))
BEGIN
RAISERROR(14262, 16, 1, 'instance_name', @instance_name)
RETURN(1) -- Failure
END
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_VERIFY_JOB_DATE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_job_date...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_job_date')
AND (type = 'P')))
DROP PROCEDURE sp_verify_job_date
go
CREATE PROCEDURE sp_verify_job_date
@date INT,
@date_name VARCHAR(60) = 'date',
@error_severity INT = -1
AS
BEGIN
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @date_name = LTRIM(RTRIM(@date_name))
IF ((ISDATE(CONVERT(VARCHAR, @date)) = 0) OR (@date < 19900101) OR (@date > 99991231))
BEGIN
RAISERROR(14266, @error_severity, -1, @date_name, '19900101..99991231')
RETURN(1) -- Failure
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_VERIFY_JOB_TIME */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_job_time...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_job_time')
AND (type = 'P')))
DROP PROCEDURE sp_verify_job_time
go
CREATE PROCEDURE sp_verify_job_time
@time INT,
@time_name VARCHAR(60) = 'time',
@error_severity INT = -1
AS
BEGIN
DECLARE @hour INT
DECLARE @minute INT
DECLARE @second INT
DECLARE @part_name NVARCHAR(50)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @time_name = LTRIM(RTRIM(@time_name))
IF ((@time < 0) OR (@time > 235959))
BEGIN
RAISERROR(14266, @error_severity, -1, @time_name, '000000..235959')
RETURN(1) -- Failure
END
SELECT @hour = (@time / 10000)
SELECT @minute = (@time % 10000) / 100
SELECT @second = (@time % 100)
-- Check hour range
IF (@hour > 23)
BEGIN
SELECT @part_name = FORMATMESSAGE(14218)
RAISERROR(14287, @error_severity, -1, @time_name, @part_name)
RETURN(1) -- Failure
END
-- Check minute range
IF (@minute > 59)
BEGIN
SELECT @part_name = FORMATMESSAGE(14219)
RAISERROR(14287, @error_severity, -1, @time_name, @part_name)
RETURN(1) -- Failure
END
-- Check second range
IF (@second > 59)
BEGIN
SELECT @part_name = FORMATMESSAGE(14220)
RAISERROR(14287, @error_severity, -1, @time_name, @part_name)
RETURN(1) -- Failure
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_VERIFY_ALERT */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_alert...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_alert')
AND (type = 'P')))
DROP PROCEDURE sp_verify_alert
go
CREATE PROCEDURE sp_verify_alert
@name sysname,
@message_id INT,
@severity INT,
@enabled TINYINT,
@delay_between_responses INT,
@notification_message NVARCHAR(512),
@include_event_description_in TINYINT,
@database_name sysname,
@event_description_keyword NVARCHAR(100),
@job_id UNIQUEIDENTIFIER OUTPUT,
@job_name sysname OUTPUT,
@occurrence_count INT,
@raise_snmp_trap TINYINT,
@performance_condition NVARCHAR(512),
@category_name sysname,
@category_id INT OUTPUT,
@count_reset_date INT,
@count_reset_time INT,
@wmi_namespace NVARCHAR(512), -- New for 9.0
@wmi_query NVARCHAR(512), -- New for 9.0
@event_id INT OUTPUT -- New for 9.0
AS
BEGIN
DECLARE @retval INT
DECLARE @non_alertable_errors VARCHAR(512)
DECLARE @message_id_as_string VARCHAR(10)
DECLARE @res_valid_range NVARCHAR(100)
DECLARE @alert_no_wmi_check INT
DECLARE @job_owner_sid VARBINARY(85)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
SELECT @notification_message = LTRIM(RTRIM(@notification_message))
SELECT @database_name = LTRIM(RTRIM(@database_name))
SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))
SELECT @job_name = LTRIM(RTRIM(@job_name))
SELECT @performance_condition = LTRIM(RTRIM(@performance_condition))
SELECT @category_name = LTRIM(RTRIM(@category_name))
SELECT @alert_no_wmi_check = 0
-- Only a sysadmin can do this
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Check if the NewName is unique
IF (EXISTS (SELECT *
FROM msdb.dbo.sysalerts
WHERE (name = @name)))
BEGIN
RAISERROR(14261, 16, 1, '@name', @name)
RETURN(1) -- Failure
END
-- Check if the user has supplied MessageID OR Severity OR Performance-Condition OR WMI namespace/query
IF ((@performance_condition IS NULL) AND (@message_id = 0) AND (@severity = 0) AND ((@wmi_namespace IS NULL) OR (@wmi_query IS NULL))) OR
((@performance_condition IS NOT NULL) AND ((@message_id <> 0) OR (@severity <> 0) OR (@wmi_namespace IS NOT NULL) OR (@wmi_query IS NOT NULL))) OR
((@message_id <> 0) AND ((@performance_condition IS NOT NULL) OR (@severity <> 0) OR (@wmi_namespace IS NOT NULL) OR (@wmi_query IS NOT NULL))) OR
((@severity <> 0) AND ((@performance_condition IS NOT NULL) OR (@message_id <> 0) OR (@wmi_namespace IS NOT NULL) OR (@wmi_query IS NOT NULL)))
BEGIN
RAISERROR(14500, 16, 1)
RETURN(1) -- Failure
END
-- Check the Severity
IF ((@severity < 0) OR (@severity > 25))
BEGIN
RAISERROR(14266, 16, 1, '@severity', '0..25')
RETURN(1) -- Failure
END
-- Check the MessageID
-- Allow if message id = 50000 (RAISERROR called with no specific message id)
IF(@message_id <> 50000)
BEGIN
IF (@message_id <> 0) AND
(NOT EXISTS (SELECT message_id
FROM sys.messages
WHERE message_id = @message_id))
BEGIN
SELECT @message_id_as_string = CONVERT(VARCHAR, @message_id)
RAISERROR(14262, 16, 1, '@message_id', @message_id_as_string)
RETURN(1) -- Failure
END
END
-- Check if it is legal to set an alert on this MessageID
DECLARE @TempRetVal TABLE (RetVal INT)
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'NonAlertableErrors',
@non_alertable_errors OUTPUT,
N'no_output'
IF (ISNULL(@non_alertable_errors, N'NULL') <> N'NULL')
BEGIN
DECLARE @message_id_as_char VARCHAR(10)
SELECT @message_id_as_char = CONVERT(VARCHAR(10), @message_id)
INSERT INTO @TempRetVal
EXECUTE ('IF (' + @message_id_as_char + ' IN (' + @non_alertable_errors + ')) SELECT 1')
END
IF (EXISTS (SELECT *
FROM @TempRetVal))
BEGIN
RAISERROR(14506, 16, 1, @message_id)
RETURN(1) -- Failure
END
-- Enabled must be 0 or 1
IF (@enabled NOT IN (0, 1))
BEGIN
RAISERROR(14266, 16, 1, '@enabled', '0, 1')
RETURN(1) -- Failure
END
-- DelayBetweenResponses must be > 0
IF (@delay_between_responses < 0)
BEGIN
SELECT @res_valid_range = FORMATMESSAGE(14206)
RAISERROR(14266, 16, 1, '@delay_between_responses', @res_valid_range)
RETURN(1) -- Failure
END
-- NOTE: We don't check the notification message
-- Check IncludeEventDescriptionIn
IF ((@include_event_description_in < 0) OR (@include_event_description_in > 7))
BEGIN
SELECT @res_valid_range = FORMATMESSAGE(14208)
RAISERROR(14266, 16, 1, '@include_event_description_in', @res_valid_range)
RETURN(1) -- Failure
END
-- Check the database name
IF (@database_name IS NOT NULL) AND (DB_ID(@database_name) IS NULL)
BEGIN
RAISERROR(15010, 16, 1, @database_name)
RETURN(1) -- Failure
END
-- NOTE: We don't check the event description keyword
-- Check JobName/ID
IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
BEGIN
-- We use '' as a special value which means 'no job' (we cannot use NULL since this forces
-- sp_update_alert to use the existing value)
IF (@job_name = N'')
SELECT @job_id = 0x00
ELSE
BEGIN
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check permissions beyond what's checked by the sysjobs_view
-- SQLAgentReaderRole and SQLAgentOperatorRole can see all jobs but
-- cannot modify them
IF (@job_owner_sid <> SUSER_SID() -- does not own the job
AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)) -- is not sysadmin
BEGIN
RAISERROR(14525, -1, -1);
RETURN(1) -- Failure
END
-- Check that the job is a local job
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)))
BEGIN
RAISERROR(14527, -1, -1, @job_name)
RETURN(1) -- Failure
END
END
END
-- OccurrenceCount must be > 0
IF (@occurrence_count < 0)
BEGIN
RAISERROR(14266, 16, 1, '@occurrence_count', '0..n')
RETURN(1) -- Failure
END
-- RaiseSNMPTrap must be 0 or 1
IF (@raise_snmp_trap NOT IN (0, 1))
BEGIN
RAISERROR(14266, 16, 1, '@raise_snmp_trap', '0, 1')
RETURN(1) -- Failure
END
-- Check the performance condition (including invalid parameter combinations)
IF (@performance_condition IS NOT NULL)
BEGIN
IF (@database_name IS NOT NULL)
BEGIN
RAISERROR(14505, 16, 1, '@database_name')
RETURN(1) -- Failure
END
IF (@event_description_keyword IS NOT NULL)
BEGIN
RAISERROR(14505, 16, 1, '@event_description_keyword')
RETURN(1) -- Failure
END
IF (@wmi_namespace IS NOT NULL)
BEGIN
RAISERROR(14505, 16, 1, '@wmi_namespace')
RETURN(1) -- Failure
END
IF (@wmi_query IS NOT NULL)
BEGIN
RAISERROR(14505, 16, 1, '@wmi_query')
RETURN(1) -- Failure
END
-- Verify the performance condition
EXECUTE @retval = msdb.dbo.sp_verify_performance_condition @performance_condition
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Check category name
IF (@category_name = N'[DEFAULT]')
SELECT @category_id = 98
ELSE
BEGIN
SELECT @category_id = category_id
FROM msdb.dbo.syscategories
WHERE (category_class = 2) -- Alerts
AND (category_type = 3) -- None
AND (name = @category_name)
END
IF (@category_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@category_name', @category_name)
RETURN(1) -- Failure
END
-- Check count reset date
IF (@count_reset_date <> 0)
BEGIN
EXECUTE @retval = msdb.dbo.sp_verify_job_date @count_reset_date, '@count_reset_date'
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Check count reset time
IF (@count_reset_time <> 0)
BEGIN
EXECUTE @retval = msdb.dbo.sp_verify_job_time @count_reset_time, '@count_reset_time'
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Check WMI parameters. Both must exist
IF (@wmi_namespace IS NOT NULL)
BEGIN
IF (@wmi_query IS NULL)
BEGIN
RAISERROR(14509, 16, 1, '@wmi_query')
RETURN(1) -- Failure
END
IF (@database_name IS NOT NULL)
BEGIN
RAISERROR(14510, 16, 1, '@database_name')
RETURN(1) -- Failure
END
IF (@event_description_keyword IS NOT NULL)
BEGIN
RAISERROR(14510, 16, 1, '@event_description_keyword')
RETURN(1) -- Failure
END
--do not check WMI properties if a registry setting is present
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'AlertNoWmiCheck',
@alert_no_wmi_check OUTPUT,
'no_output'
if (@alert_no_wmi_check <> 1)
BEGIN
EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type = N'T',
@wmi_namespace = @wmi_namespace,
@wmi_query = @wmi_query,
@error_flag = 0
IF (@retval <> 0)
BEGIN
RAISERROR(14511, 16, 1)
RETURN(1) -- Failure
END
END
-- Set event_id to indicate WMI alert
SELECT @event_id = 8
END
ELSE IF (@wmi_query IS NOT NULL)
BEGIN
RAISERROR(14512, 16, 1, '@wmi_namespace')
RETURN(1) -- Failure
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_UPDATE_ALERT */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_alert...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_update_alert')
AND (type = 'P')))
DROP PROCEDURE sp_update_alert
go
CREATE PROCEDURE sp_update_alert
@name sysname,
@new_name sysname = NULL,
@enabled TINYINT = NULL,
@message_id INT = NULL,
@severity INT = NULL,
@delay_between_responses INT = NULL,
@notification_message NVARCHAR(512) = NULL,
@include_event_description_in TINYINT = NULL, -- 0 = None, 1 = Email, 2 = Pager. 4 = NetSend, 7 = All
@database_name sysname = NULL,
@event_description_keyword NVARCHAR(100) = NULL,
@job_id UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name
@job_name sysname = NULL, -- If provided must NOT also provide job_id
@occurrence_count INT = NULL, -- Can only be set to 0
@count_reset_date INT = NULL,
@count_reset_time INT = NULL,
@last_occurrence_date INT = NULL, -- Can only be set to 0
@last_occurrence_time INT = NULL, -- Can only be set to 0
@last_response_date INT = NULL, -- Can only be set to 0
@last_response_time INT = NULL, -- Can only be set to 0
@raise_snmp_trap TINYINT = NULL,
@performance_condition NVARCHAR(512) = NULL, -- New for 7.0
@category_name sysname = NULL, -- New for 7.0
@wmi_namespace sysname = NULL, -- New for 9.0
@wmi_query NVARCHAR(512) = NULL -- New for 9.0
AS
BEGIN
DECLARE @x_enabled TINYINT
DECLARE @x_message_id INT
DECLARE @x_severity INT
DECLARE @x_delay_between_responses INT
DECLARE @x_notification_message NVARCHAR(512)
DECLARE @x_include_event_description TINYINT
DECLARE @x_database_name sysname
DECLARE @x_event_description_keyword NVARCHAR(100)
DECLARE @x_occurrence_count INT
DECLARE @x_count_reset_date INT
DECLARE @x_count_reset_time INT
DECLARE @x_last_occurrence_date INT
DECLARE @x_last_occurrence_time INT
DECLARE @x_last_response_date INT
DECLARE @x_last_response_time INT
DECLARE @x_flags INT
DECLARE @x_performance_condition NVARCHAR(512)
DECLARE @x_job_id UNIQUEIDENTIFIER
DECLARE @x_category_id INT
DECLARE @x_event_id INT
DECLARE @x_wmi_namespace sysname
DECLARE @x_wmi_query NVARCHAR(512)
DECLARE @include_event_desc_code TINYINT
DECLARE @return_code INT
DECLARE @duplicate_name sysname
DECLARE @category_id INT
DECLARE @alert_id INT
DECLARE @cached_attribute_modified INT
DECLARE @event_id INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @new_name = LTRIM(RTRIM(@new_name))
SELECT @job_name = LTRIM(RTRIM(@job_name))
SELECT @notification_message = LTRIM(RTRIM(@notification_message))
SELECT @database_name = LTRIM(RTRIM(@database_name))
SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))
SELECT @performance_condition = LTRIM(RTRIM(@performance_condition))
SELECT @category_name = LTRIM(RTRIM(@category_name))
-- Are we modifying an attribute which SQLServerAgent caches?
IF ((@new_name IS NOT NULL) OR
(@enabled IS NOT NULL) OR
(@message_id IS NOT NULL) OR
(@severity IS NOT NULL) OR
(@delay_between_responses IS NOT NULL) OR
(@notification_message IS NOT NULL) OR
(@include_event_description_in IS NOT NULL) OR
(@database_name IS NOT NULL) OR
(@event_description_keyword IS NOT NULL) OR
(@job_id IS NOT NULL) OR
(@job_name IS NOT NULL) OR
(@last_response_date IS NOT NULL) OR
(@last_response_time IS NOT NULL) OR
(@raise_snmp_trap IS NOT NULL) OR
(@performance_condition IS NOT NULL) OR
(@wmi_namespace IS NOT NULL) OR
(@wmi_query IS NOT NULL))
SELECT @cached_attribute_modified = 1
ELSE
SELECT @cached_attribute_modified = 0
-- Map a job_id of 0 to the real value we use to mean 'no job'
IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND (@job_name IS NULL)
SELECT @job_name = N''
-- Only a sysadmin can do this
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1)
END
-- Check if SQLServerAgent is in the process of starting
EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting
IF (@return_code <> 0)
RETURN(1) -- Failure
-- Check if this Alert exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysalerts
WHERE (name = @name)))
BEGIN
RAISERROR(14262, 16, 1, '@name', @name)
RETURN(1)
END
-- Certain values (if supplied) may only be updated to 0
IF (@occurrence_count <> 0)
BEGIN
RAISERROR(14266, -1, -1, '@occurrence_count', '0')
RETURN(1) -- Failure
END
IF (@last_occurrence_date <> 0)
BEGIN
RAISERROR(14266, -1, -1, '@last_occurrence_date', '0')
RETURN(1) -- Failure
END
IF (@last_occurrence_time <> 0)
BEGIN
RAISERROR(14266, -1, -1, '@last_occurrence_time', '0')
RETURN(1) -- Failure
END
IF (@last_response_date <> 0)
BEGIN
RAISERROR(14266, -1, -1, '@last_response_date', '0')
RETURN(1) -- Failure
END
IF (@last_response_time <> 0)
BEGIN
RAISERROR(14266, -1, -1, '@last_response_time', '0')
RETURN(1) -- Failure
END
-- Get existing (@x_) values
SELECT @alert_id = id,
@x_enabled = enabled,
@x_message_id = message_id,
@x_severity = severity,
@x_delay_between_responses = delay_between_responses,
@x_notification_message = notification_message,
@x_include_event_description = include_event_description,
@x_database_name = database_name,
@x_event_description_keyword = event_description_keyword,
@x_occurrence_count = occurrence_count,
@x_count_reset_date = count_reset_date,
@x_count_reset_time = count_reset_time,
@x_job_id = job_id,
@x_last_occurrence_date = last_occurrence_date,
@x_last_occurrence_time = last_occurrence_time,
@x_last_response_date = last_response_date,
@x_last_response_time = last_response_time,
@x_flags = flags,
@x_performance_condition = performance_condition,
@x_category_id = category_id,
@x_event_id = event_id
FROM msdb.dbo.sysalerts
WHERE (name = @name)
SELECT @x_job_id = sjv.job_id
FROM msdb.dbo.sysalerts sa,
msdb.dbo.sysjobs_view sjv
WHERE (sa.job_id = sjv.job_id)
AND (sa.name = @name)
-- Fill out the values for all non-supplied parameters from the existsing values
IF (@x_event_id = 8)
BEGIN
-- WMI alert type
IF (@wmi_namespace IS NULL) SELECT @wmi_namespace = @x_database_name
IF (@wmi_query IS NULL) SELECT @wmi_query = @x_performance_condition
END
ELSE
BEGIN
-- Non-WMI alert type
IF (@database_name IS NULL) SELECT @database_name = @x_database_name
IF (@performance_condition IS NULL) SELECT @performance_condition = @x_performance_condition
END
IF (@enabled IS NULL) SELECT @enabled = @x_enabled
IF (@message_id IS NULL) SELECT @message_id = @x_message_id
IF (@severity IS NULL) SELECT @severity = @x_severity
IF (@delay_between_responses IS NULL) SELECT @delay_between_responses = @x_delay_between_responses
IF (@notification_message IS NULL) SELECT @notification_message = @x_notification_message
IF (@include_event_description_in IS NULL) SELECT @include_event_description_in = @x_include_event_description
IF (@event_description_keyword IS NULL) SELECT @event_description_keyword = @x_event_description_keyword
IF (@job_id IS NULL) AND (@job_name IS NULL) SELECT @job_id = @x_job_id
IF (@occurrence_count IS NULL) SELECT @occurrence_count = @x_occurrence_count
IF (@count_reset_date IS NULL) SELECT @count_reset_date = @x_count_reset_date
IF (@count_reset_time IS NULL) SELECT @count_reset_time = @x_count_reset_time
IF (@last_occurrence_date IS NULL) SELECT @last_occurrence_date = @x_last_occurrence_date
IF (@last_occurrence_time IS NULL) SELECT @last_occurrence_time = @x_last_occurrence_time
IF (@last_response_date IS NULL) SELECT @last_response_date = @x_last_response_date
IF (@last_response_time IS NULL) SELECT @last_response_time = @x_last_response_time
IF (@raise_snmp_trap IS NULL) SELECT @raise_snmp_trap = @x_flags & 0x1
IF (@category_name IS NULL) SELECT @category_name = name FROM msdb.dbo.syscategories WHERE (category_id = @x_category_id)
IF (@category_name IS NULL)
BEGIN
SELECT @category_name = name
FROM msdb.dbo.syscategories
WHERE (category_id = 98)
END
-- Turn [nullable] empty string parameters into NULLs
IF (@new_name = N'') SELECT @new_name = NULL
IF (@notification_message = N'') SELECT @notification_message = NULL
IF (@database_name = N'') SELECT @database_name = NULL
IF (@event_description_keyword = N'') SELECT @event_description_keyword = NULL
IF (@performance_condition = N'') SELECT @performance_condition = NULL
IF (@wmi_namespace = N'') SELECT @wmi_namespace = NULL
IF (@wmi_query = N'') SELECT @wmi_query = NULL
-- Verify the Alert
IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00))
SELECT @job_id = NULL
EXECUTE @return_code = sp_verify_alert @new_name,
@message_id,
@severity,
@enabled,
@delay_between_responses,
@notification_message,
@include_event_description_in,
@database_name,
@event_description_keyword,
@job_id OUTPUT,
@job_name OUTPUT,
@occurrence_count,
@raise_snmp_trap,
@performance_condition,
@category_name,
@category_id OUTPUT,
@count_reset_date,
@count_reset_time,
@wmi_namespace,
@wmi_query,
@event_id OUTPUT
IF (@return_code <> 0)
RETURN(1) -- Failure
-- If the user didn't supply a NewName, use the old one.
-- NOTE: This must be done AFTER sp_verify_alert.
IF (@new_name IS NULL)
SELECT @new_name = @name
-- Turn the 1st 'flags' bit on or off accordingly
IF (@raise_snmp_trap = 0)
SELECT @x_flags = @x_flags & 0xFFFE
ELSE
SELECT @x_flags = @x_flags | 0x0001
-- For WMI alerts replace
-- database_name with wmi_namespace and
-- performance_conditon with wmi_query
-- so we can store them in those columns in sysalerts table
IF (@event_id = 8)
BEGIN
SELECT @database_name = @wmi_namespace
SELECT @performance_condition = @wmi_query
END
-- Check if this Alert already exists
SELECT @duplicate_name = FORMATMESSAGE(14205)
SELECT @duplicate_name = name
FROM msdb.dbo.sysalerts
WHERE ((event_id = 8) AND
(ISNULL(performance_condition, N'') = ISNULL(@performance_condition, N'')) AND
(ISNULL(database_name, N'') = ISNULL(@database_name, N''))) OR
((ISNULL(event_id,1) <> 8) AND
(ISNULL(performance_condition, N'apples') = ISNULL(@performance_condition, N'oranges'))) OR
((performance_condition IS NULL) AND
(message_id = @message_id) AND
(severity = @severity) AND
(ISNULL(database_name, N'') = ISNULL(@database_name, N'')) AND
(ISNULL(event_description_keyword, N'') = ISNULL(@event_description_keyword, N'')))
IF (@duplicate_name <> FORMATMESSAGE(14205) AND @duplicate_name <> @name)
BEGIN
RAISERROR(14501, 16, 1, @duplicate_name)
RETURN(1) -- Failure
END
-- Finally, do the actual UPDATE
UPDATE msdb.dbo.sysalerts
SET name = @new_name,
message_id = @message_id,
severity = @severity,
enabled = @enabled,
delay_between_responses = @delay_between_responses,
notification_message = @notification_message,
include_event_description = @include_event_description_in,
database_name = @database_name,
event_description_keyword = @event_description_keyword,
job_id = ISNULL(@job_id, CONVERT(UNIQUEIDENTIFIER, 0x00)),
occurrence_count = @occurrence_count,
count_reset_date = @count_reset_date,
count_reset_time = @count_reset_time,
last_occurrence_date = @last_occurrence_date,
last_occurrence_time = @last_occurrence_time,
last_response_date = @last_response_date,
last_response_time = @last_response_time,
flags = @x_flags,
performance_condition = @performance_condition,
category_id = @category_id,
event_id = @event_id
WHERE (name = @name)
-- Notify SQLServerAgent of the change
IF (@cached_attribute_modified = 1)
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',
@alert_id = @alert_id,
@action_type = N'U'
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_DELETE_JOB_REFERENCES */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_job_references...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_job_references')
AND (type = 'P')))
DROP PROCEDURE sp_delete_job_references
go
CREATE PROCEDURE sp_delete_job_references
@notify_sqlagent BIT = 1
AS
BEGIN
DECLARE @deleted_job_id UNIQUEIDENTIFIER
DECLARE @task_id_as_char VARCHAR(10)
DECLARE @job_is_cached INT
DECLARE @alert_name sysname
DECLARE @maintplan_plan_id UNIQUEIDENTIFIER
DECLARE @maintplan_subplan_id UNIQUEIDENTIFIER
-- Keep SQLServerAgent's cache in-sync and cleanup any 'webtask' cross-references to the deleted job(s)
-- NOTE: The caller must have created a table called #temp_jobs_to_delete of the format
-- (job_id UNIQUEIDENTIFIER NOT NULL, job_is_cached INT NOT NULL).
DECLARE sqlagent_notify CURSOR LOCAL
FOR
SELECT job_id, job_is_cached
FROM #temp_jobs_to_delete
OPEN sqlagent_notify
FETCH NEXT FROM sqlagent_notify INTO @deleted_job_id, @job_is_cached
WHILE (@@fetch_status = 0)
BEGIN
-- NOTE: We only notify SQLServerAgent if we know the job has been cached
IF(@job_is_cached = 1 AND @notify_sqlagent = 1)
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',
@job_id = @deleted_job_id,
@action_type = N'D'
IF (EXISTS (SELECT *
FROM master.dbo.sysobjects
WHERE (name = N'sp_cleanupwebtask')
AND (type = 'P')))
BEGIN
SELECT @task_id_as_char = CONVERT(VARCHAR(10), task_id)
FROM msdb.dbo.systaskids
WHERE (job_id = @deleted_job_id)
IF (@task_id_as_char IS NOT NULL)
EXECUTE ('master.dbo.sp_cleanupwebtask @taskid = ' + @task_id_as_char)
END
-- Maintenance plan cleanup for SQL 2005.
-- If this job came from another server and it runs a subplan of a
-- maintenance plan, then delete the subplan record. If that was
-- the last subplan still referencing that plan, delete the plan.
-- This removes a distributed maintenance plan from a target server
-- once all of jobs from the master server that used that maintenance
-- plan are deleted.
SELECT @maintplan_plan_id = plans.plan_id, @maintplan_subplan_id = plans.subplan_id
FROM sysmaintplan_subplans plans, sysjobs_view sjv
WHERE plans.job_id = @deleted_job_id
AND plans.job_id = sjv.job_id
AND sjv.master_server = 1 -- This means the job came from the master
IF (@maintplan_subplan_id is not NULL)
BEGIN
EXECUTE sp_maintplan_delete_subplan @subplan_id = @maintplan_subplan_id, @delete_jobs = 0
IF (NOT EXISTS (SELECT *
FROM sysmaintplan_subplans
where plan_id = @maintplan_plan_id))
BEGIN
DECLARE @plan_name sysname
SELECT @plan_name = name
FROM sysmaintplan_plans
WHERE id = @maintplan_plan_id
EXECUTE sp_ssis_deletepackage @name = @plan_name, @folderid = '08aa12d5-8f98-4dab-a4fc-980b150a5dc8' -- this is the guid for 'Maintenance Plans'
END
END
FETCH NEXT FROM sqlagent_notify INTO @deleted_job_id, @job_is_cached
END
DEALLOCATE sqlagent_notify
-- Remove systaskid references (must do this AFTER sp_cleanupwebtask stuff)
DELETE FROM msdb.dbo.systaskids
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
-- Remove sysdbmaintplan_jobs references (legacy maintenance plans prior to SQL 2005)
DELETE FROM msdb.dbo.sysdbmaintplan_jobs
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
-- Finally, clean up any dangling references in sysalerts to the deleted job(s)
DECLARE sysalerts_cleanup CURSOR LOCAL
FOR
SELECT name
FROM msdb.dbo.sysalerts
WHERE (job_id IN (SELECT job_id FROM #temp_jobs_to_delete))
OPEN sysalerts_cleanup
FETCH NEXT FROM sysalerts_cleanup INTO @alert_name
WHILE (@@fetch_status = 0)
BEGIN
EXECUTE msdb.dbo.sp_update_alert @name = @alert_name,
@job_id = 0x00
FETCH NEXT FROM sysalerts_cleanup INTO @alert_name
END
DEALLOCATE sysalerts_cleanup
END
go
/**************************************************************/
/* SP_DELETE_ALL_MSX_JOBS */
/* */
/* NOTE: This is a separate procedure because SQLServerAgent */
/* needs to call it, as does sp_msx_defect and */
/* sp_delete_job. */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_all_msx_jobs...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_all_msx_jobs')
AND (type = 'P')))
DROP PROCEDURE sp_delete_all_msx_jobs
go
CREATE PROCEDURE sp_delete_all_msx_jobs
@msx_server sysname,
@jobs_deleted INT = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON
-- Change server name to always reflect real servername or servername\instancename
IF (UPPER(@msx_server collate SQL_Latin1_General_CP1_CS_AS) = '(LOCAL)')
SELECT @msx_server = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))
-- Delete all the jobs that originated from the MSX
-- Note: This temp table is referenced by msdb.dbo.sp_delete_job_references
CREATE TABLE #temp_jobs_to_delete (job_id UNIQUEIDENTIFIER NOT NULL, job_is_cached INT NOT NULL, owner_sid VARBINARY(85) NOT NULL)
-- Table of msx schedules to delete
DECLARE @temp_schedules_to_delete TABLE (schedule_id INT NOT NULL)
-- Non-sysadmins can only delete jobs they own. sysjobs_view returns all jobs
-- for members of SQLAgentReaderRole and SQLAgentOperatorRole, but they should
-- not be able to delete those jobs
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1))
BEGIN
-- NOTE: The left outer-join here is to handle the [unlikely] case of missing sysjobservers rows
INSERT INTO #temp_jobs_to_delete
SELECT sjv.job_id,
CASE sjs.server_id WHEN 0 THEN 1 ELSE 0 END,
sjv.owner_sid
FROM msdb.dbo.sysjobs_view sjv
LEFT OUTER JOIN msdb.dbo.sysjobservers sjs ON (sjv.job_id = sjs.job_id)
WHERE (ISNULL(sjs.server_id, 0) = 0)
AND (sjv.originating_server = @msx_server)
END
ELSE
BEGIN
-- NOTE: The left outer-join here is to handle the [unlikely] case of missing sysjobservers rows
INSERT INTO #temp_jobs_to_delete
SELECT sjv.job_id,
CASE sjs.server_id WHEN 0 THEN 1 ELSE 0 END,
sjv.owner_sid
FROM msdb.dbo.sysjobs_view sjv
LEFT OUTER JOIN msdb.dbo.sysjobservers sjs ON (sjv.job_id = sjs.job_id)
WHERE (ISNULL(sjs.server_id, 0) = 0)
AND (sjv.originating_server = @msx_server)
AND (sjv.owner_sid = SUSER_SID())
END
-- Must do this before deleting the job itself since sp_sqlagent_notify does a lookup on sysjobs_view
EXECUTE msdb.dbo.sp_delete_job_references
BEGIN TRANSACTION
--Get the list of schedules to delete, these cant be deleted until the references are deleted in sysjobschedules
INSERT INTO @temp_schedules_to_delete
SELECT DISTINCT schedule_id
FROM msdb.dbo.sysschedules
WHERE (schedule_id IN
(SELECT schedule_id
FROM msdb.dbo.sysjobschedules as js
JOIN #temp_jobs_to_delete as tjd ON (js.job_id = tjd.job_id)))
DELETE FROM msdb.dbo.sysjobschedules
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
--Now OK to delete the schedule
DELETE FROM msdb.dbo.sysschedules
WHERE schedule_id IN
(SELECT schedule_id
FROM @temp_schedules_to_delete)
DELETE FROM msdb.dbo.sysjobservers
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
DELETE FROM msdb.dbo.sysjobsteps
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
DELETE FROM msdb.dbo.sysjobs
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
DELETE FROM msdb.dbo.sysjobhistory
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
--Finally cleanup any orphaned sysschedules that were downloaded from the MSX
DELETE msdb.dbo.sysschedules
FROM msdb.dbo.sysschedules s
JOIN msdb.dbo.sysoriginatingservers_view os ON (s.originating_server_id = os.originating_server_id)
WHERE (os.originating_server = @msx_server)
COMMIT TRANSACTION
SELECT @jobs_deleted = COUNT(*)
FROM #temp_jobs_to_delete
DROP TABLE #temp_jobs_to_delete
END
go
/**************************************************************/
/* SP_GENERATE_TARGET_SERVER_JOB_ASSIGNMENT_SQL */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_generate_target_server_job_assignment_sql...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_generate_target_server_job_assignment_sql')
AND (type = 'P')))
DROP PROCEDURE sp_generate_target_server_job_assignment_sql
go
CREATE PROCEDURE sp_generate_target_server_job_assignment_sql
@server_name sysname = NULL,
@new_server_name sysname = NULL -- Use this if the target server computer has been renamed
AS
BEGIN
SET NOCOUNT ON
-- Change server name to always reflect real servername or servername\instancename
IF (@server_name IS NULL) OR (UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = '(LOCAL)')
SELECT @server_name = CONVERT(sysname, SERVERPROPERTY('ServerName'))
IF (@server_name IS NOT NULL)
SELECT @server_name = UPPER(@server_name)
-- Verify the server name
IF (@server_name <> UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))) AND
(NOT EXISTS (SELECT *
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = @server_name)))
BEGIN
RAISERROR(14262, 16, 1, '@server_name', @server_name)
RETURN(1) -- Failure
END
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers sjs,
msdb.dbo.systargetservers sts
WHERE (sjs.server_id = sts.server_id)
AND (UPPER(sts.server_name) = @server_name)))
BEGIN
-- Generate the SQL
SELECT 'Execute this SQL to re-assign jobs to the target server' =
'EXECUTE msdb.dbo.sp_add_jobserver @job_id = ''' + CONVERT(VARCHAR(36), sjs.job_id) +
''', @server_name = ''' + ISNULL(@new_server_name, sts.server_name) + ''''
FROM msdb.dbo.sysjobservers sjs,
msdb.dbo.systargetservers sts
WHERE (sjs.server_id = sts.server_id)
AND (UPPER(sts.server_name) = @server_name)
END
ELSE
RAISERROR(14548, 10, 1, @server_name)
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_GENERATE_SERVER_DESCRIPTION */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_generate_server_description...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_generate_server_description')
AND (type = 'P')))
DROP PROCEDURE sp_generate_server_description
go
CREATE PROCEDURE sp_generate_server_description
@description NVARCHAR(100) = NULL OUTPUT,
@result_set BIT = 0
AS
BEGIN
SET NOCOUNT ON
DECLARE @xp_results TABLE
(
id INT NOT NULL,
name NVARCHAR(30) COLLATE database_default NOT NULL,
internal_value INT NULL,
character_value NVARCHAR(212) COLLATE database_default NULL
)
INSERT INTO @xp_results
EXECUTE master.dbo.xp_msver
UPDATE @xp_results
SET character_value = FORMATMESSAGE(14205)
WHERE (character_value IS NULL)
SELECT @description = (SELECT character_value FROM @xp_results WHERE (id = 1)) + N' ' +
(SELECT character_value FROM @xp_results WHERE (id = 2)) + N' / Windows ' +
(SELECT character_value FROM @xp_results WHERE (id = 15)) + N' / ' +
(SELECT character_value FROM @xp_results WHERE (id = 16)) + N' ' +
(SELECT CASE character_value
WHEN N'PROCESSOR_INTEL_386' THEN N'386'
WHEN N'PROCESSOR_INTEL_486' THEN N'486'
WHEN N'PROCESSOR_INTEL_PENTIUM' THEN N'Pentium'
WHEN N'PROCESSOR_MIPS_R4000' THEN N'MIPS'
WHEN N'PROCESSOR_ALPHA_21064' THEN N'Alpha'
ELSE character_value
END
FROM @xp_results WHERE (id = 18)) + N' CPU(s) / ' +
(SELECT CONVERT(NVARCHAR, internal_value) FROM @xp_results WHERE (id = 19)) + N' MB RAM.'
IF (@result_set = 1)
SELECT @description
END
go
/**************************************************************/
/* SP_MSX_SET_ACCOUNT */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_msx_set_account...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_msx_set_account')
AND (type = 'P')))
DROP PROCEDURE sp_msx_set_account
go
CREATE PROCEDURE sp_msx_set_account
@credential_name sysname = NULL,
@credential_id INT = NULL
AS
BEGIN
DECLARE @retval INT
IF @credential_id IS NOT NULL OR @credential_name IS NOT NULL
BEGIN
EXECUTE @retval = sp_verify_credential_identifiers '@credential_name',
'@credential_id',
@credential_name OUTPUT,
@credential_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
--set credential_id to agent registry
EXECUTE master.dbo.xp_instance_regwrite 'HKEY_LOCAL_MACHINE',
'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
'MSXCredentialID',
'REG_DWORD',
@credential_id
--set connections to standard
EXECUTE master.dbo.xp_instance_regwrite 'HKEY_LOCAL_MACHINE',
'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
'RegularMSXConnections',
'REG_DWORD',
1
END
ELSE
BEGIN
--just set connection to integrated
EXECUTE master.dbo.xp_instance_regwrite 'HKEY_LOCAL_MACHINE',
'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
'RegularMSXConnections',
'REG_DWORD',
0
END
END
go
/**************************************************************/
/* SP_MSX_GET_ACCOUNT */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_msx_get_account...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_msx_get_account')
AND (type = 'P')))
DROP PROCEDURE sp_msx_get_account
go
CREATE PROCEDURE sp_msx_get_account
AS
BEGIN
DECLARE @msx_connection INT
DECLARE @credential_id INT
SELECT @msx_connection = 0 --integrated connections
SELECT @credential_id = NULL
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'RegularMSXConnections',
@msx_connection OUTPUT,
N'no_output'
IF @msx_connection = 1
BEGIN
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXCredentialID',
@credential_id OUTPUT,
N'no_output'
SELECT msx_connection = @msx_connection , msx_credential_id = @credential_id,
msx_credential_name = sc.name , msx_login_name = sc.credential_identity
FROM master.sys.credentials sc
WHERE credential_id = @credential_id
END
END
go
/**************************************************************/
/* SP_DELETE_OPERATOR */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_operator...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_operator')
AND (type = 'P')))
DROP PROCEDURE sp_delete_operator
go
CREATE PROCEDURE sp_delete_operator
@name sysname,
@reassign_to_operator sysname = NULL
AS
BEGIN
DECLARE @id INT
DECLARE @alert_fail_safe_operator sysname
DECLARE @job_id UNIQUEIDENTIFIER
DECLARE @job_id_as_char VARCHAR(36)
DECLARE @notify_email_operator_id INT
DECLARE @notify_netsend_operator_id INT
DECLARE @notify_page_operator_id INT
DECLARE @reassign_to_id INT
DECLARE @cmd NVARCHAR(1000)
DECLARE @current_msx_server sysname
DECLARE @reassign_to_escaped NVARCHAR(256)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
SELECT @reassign_to_operator = LTRIM(RTRIM(@reassign_to_operator))
-- Turn [nullable] empty string parameters into NULLs
IF (@reassign_to_operator = N'') SELECT @reassign_to_operator = NULL
-- Only a sysadmin can do this
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Check if this Operator exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysoperators
WHERE (name = @name)))
BEGIN
RAISERROR(14262, 16, 1, '@name', @name)
RETURN(1) -- Failure
END
-- Check if this operator the FailSafe Operator
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'AlertFailSafeOperator',
@alert_fail_safe_operator OUTPUT,
N'no_output'
-- If it is, we disallow the delete operation
IF (LTRIM(RTRIM(@alert_fail_safe_operator)) = @name)
BEGIN
RAISERROR(14504, 16, 1, @name, @name)
RETURN(1) -- Failure
END
-- Check if this operator is 'MSXOperator'
IF (@name = N'MSXOperator')
BEGIN
DECLARE @server_type VARCHAR(3)
-- Disallow the delete operation if we're an MSX or a TSX
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServerName',
@current_msx_server OUTPUT,
N'no_output'
IF (@current_msx_server IS NOT NULL)
SELECT @server_type = 'TSX'
IF ((SELECT COUNT(*)
FROM msdb.dbo.systargetservers) > 0)
SELECT @server_type = 'MSX'
IF (@server_type IS NOT NULL)
BEGIN
RAISERROR(14223, 16, 1, 'MSXOperator', @server_type)
RETURN(1) -- Failure
END
END
-- Convert the Name to it's ID
SELECT @id = id
FROM msdb.dbo.sysoperators
WHERE (name = @name)
IF (@reassign_to_operator IS NOT NULL)
BEGIN
-- On a TSX or standalone server, disallow re-assigning to the MSXOperator
IF (@reassign_to_operator = N'MSXOperator') AND
(NOT EXISTS (SELECT *
FROM msdb.dbo.systargetservers))
BEGIN
RAISERROR(14251, -1, -1, @reassign_to_operator)
RETURN(1) -- Failure
END
SELECT @reassign_to_id = id
FROM msdb.dbo.sysoperators
WHERE (name = @reassign_to_operator)
IF (@reassign_to_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@reassign_to_operator', @reassign_to_operator)
RETURN(1) -- Failure
END
END
-- Double up any single quotes in @reassign_to_operator
IF (@reassign_to_operator IS NOT NULL)
SET @reassign_to_escaped = REPLACE(@reassign_to_operator, N'''', N'''''')
BEGIN TRANSACTION
-- Reassign (or delete) any sysnotifications rows that reference this operator
IF (@reassign_to_operator IS NOT NULL)
BEGIN
UPDATE msdb.dbo.sysnotifications
SET operator_id = @reassign_to_id
WHERE (operator_id = @id)
AND (NOT EXISTS (SELECT *
FROM msdb.dbo.sysnotifications sn2
WHERE (sn2.alert_id = msdb.dbo.sysnotifications.alert_id)
AND (sn2.operator_id = @reassign_to_id)))
END
DELETE FROM msdb.dbo.sysnotifications
WHERE (operator_id = @id)
-- Update any jobs that reference this operator
DECLARE jobs_referencing_this_operator CURSOR LOCAL
FOR
SELECT job_id,
notify_email_operator_id,
notify_netsend_operator_id,
notify_page_operator_id
FROM msdb.dbo.sysjobs
WHERE (notify_email_operator_id = @id)
OR (notify_netsend_operator_id = @id)
OR (notify_page_operator_id = @id)
OPEN jobs_referencing_this_operator
FETCH NEXT FROM jobs_referencing_this_operator INTO @job_id,
@notify_email_operator_id,
@notify_netsend_operator_id,
@notify_page_operator_id
WHILE (@@fetch_status = 0)
BEGIN
SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
SELECT @cmd = N'msdb.dbo.sp_update_job @job_id = ''' + @job_id_as_char + N''', '
IF (@notify_email_operator_id = @id)
IF (@reassign_to_operator IS NOT NULL)
SELECT @cmd = @cmd + N'@notify_email_operator_name = N''' + @reassign_to_escaped + N''', '
ELSE
SELECT @cmd = @cmd + N'@notify_email_operator_name = N'''', @notify_level_email = 0, '
IF (@notify_netsend_operator_id = @id)
IF (@reassign_to_operator IS NOT NULL)
SELECT @cmd = @cmd + N'@notify_netsend_operator_name = N''' + @reassign_to_escaped + N''', '
ELSE
SELECT @cmd = @cmd + N'@notify_netsend_operator_name = N'''', @notify_level_netsend = 0, '
IF (@notify_page_operator_id = @id)
IF (@reassign_to_operator IS NOT NULL)
SELECT @cmd = @cmd + N'@notify_page_operator_name = N''' + @reassign_to_escaped + N''', '
ELSE
SELECT @cmd = @cmd + N'@notify_page_operator_name = N'''', @notify_level_page = 0, '
SELECT @cmd = SUBSTRING(@cmd, 1, (DATALENGTH(@cmd) / 2) - 2)
EXECUTE (N'EXECUTE ' + @cmd)
FETCH NEXT FROM jobs_referencing_this_operator INTO @job_id,
@notify_email_operator_id,
@notify_netsend_operator_id,
@notify_page_operator_id
END
DEALLOCATE jobs_referencing_this_operator
-- Finally, do the actual DELETE
DELETE FROM msdb.dbo.sysoperators
WHERE (id = @id)
COMMIT TRANSACTION
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_MSX_DEFECT */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_msx_defect...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_msx_defect')
AND (type = 'P')))
DROP PROCEDURE sp_msx_defect
go
CREATE PROCEDURE sp_msx_defect
@forced_defection BIT = 0
AS
BEGIN
DECLARE @current_msx_server sysname
DECLARE @retval INT
DECLARE @jobs_deleted INT
DECLARE @polling_interval INT
DECLARE @nt_user NVARCHAR(100)
SET NOCOUNT ON
-- Only a sysadmin can do this
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
SELECT @retval = 0
SELECT @jobs_deleted = 0
-- Get the current MSX server name from the registry
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServerName',
@current_msx_server OUTPUT,
N'no_output'
SELECT @current_msx_server = UPPER(LTRIM(RTRIM(@current_msx_server)))
IF ((@current_msx_server IS NULL) OR (@current_msx_server = N''))
BEGIN
RAISERROR(14298, -1, -1)
RETURN(1) -- Failure
END
SELECT @nt_user = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))
EXECUTE @retval = master.dbo.xp_msx_enlist 1, @current_msx_server, @nt_user
IF (@retval <> 0) AND (@forced_defection = 0)
RETURN(1) -- Failure
-- Clear the MSXServerName registry entry
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServerName',
N'REG_SZ',
N''
-- Delete the MSXPollingInterval registry entry
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXPollInterval',
@polling_interval OUTPUT,
N'no_output'
IF (@polling_interval IS NOT NULL)
EXECUTE master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXPollInterval'
-- Remove the entry from sqlagent_info
DELETE FROM msdb.dbo.sqlagent_info
WHERE (attribute = N'DateEnlisted')
-- Delete all the jobs that originated from the MSX
-- NOTE: We can't use sp_delete_job here since sp_delete_job checks if the caller is
-- SQLServerAgent (only SQLServerAgent can delete non-local jobs).
EXECUTE msdb.dbo.sp_delete_all_msx_jobs @current_msx_server, @jobs_deleted OUTPUT
RAISERROR(14227, 0, 1, @current_msx_server, @jobs_deleted)
-- Now delete the old msx server record
DELETE msdb.dbo.sysoriginatingservers
WHERE (originating_server = @current_msx_server)
AND (master_server = 1)
-- If a forced defection was performed, attempt to notify the MSXOperator
IF (@forced_defection = 1)
BEGIN
DECLARE @network_address NVARCHAR(100)
DECLARE @command NVARCHAR(512)
DECLARE @local_machine_name sysname
DECLARE @res_warning NVARCHAR(300)
SELECT @network_address = netsend_address
FROM msdb.dbo.sysoperators
WHERE (name = N'MSXOperator')
IF (@network_address IS NOT NULL)
BEGIN
EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
SELECT @res_warning = FORMATMESSAGE(14217)
SELECT @command = N'NET SEND ' + @network_address + N' ' + @res_warning
SELECT @command = STUFF(@command, PATINDEX(N'%[%%]s%', @command), 2, NT_CLIENT())
SELECT @command = STUFF(@command, PATINDEX(N'%[%%]s%', @command), 2, @local_machine_name)
EXECUTE master.dbo.xp_cmdshell @command, no_output
END
END
-- Delete the 'MSXOperator' (must do this last)
IF (EXISTS (SELECT *
FROM msdb.dbo.sysoperators
WHERE (name = N'MSXOperator')))
EXECUTE msdb.dbo.sp_delete_operator @name = N'MSXOperator'
RETURN(0) -- 0 means success
END
go
/**************************************************************/
/* SP_MSX_ENLIST */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_msx_enlist...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_msx_enlist')
AND (type = 'P')))
DROP PROCEDURE sp_msx_enlist
go
CREATE PROCEDURE sp_msx_enlist
@msx_server_name sysname,
@location NVARCHAR(100) = NULL -- The procedure will supply a default
AS
BEGIN
DECLARE @current_msx_server sysname
DECLARE @local_machine_name sysname
DECLARE @msx_originating_server sysname
DECLARE @retval INT
DECLARE @time_zone_adjustment INT
DECLARE @local_time NVARCHAR(100)
DECLARE @nt_user NVARCHAR(100)
DECLARE @poll_interval INT
SET NOCOUNT ON
-- Only a sysadmin can do this
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Only an NT server can be enlisted
IF ((PLATFORM() & 0x1) <> 0x1) -- NT
BEGIN
RAISERROR(14540, -1, 1)
RETURN(1) -- Failure
END
-- Only SBS, Standard, or Enterprise editions of SQL Server can be enlisted
IF ((PLATFORM() & 0x100) = 0x100) -- Desktop package
BEGIN
RAISERROR(14539, -1, -1)
RETURN(1) -- Failure
END
-- Remove any leading/trailing spaces from parameters
SELECT @msx_server_name = UPPER(LTRIM(RTRIM(@msx_server_name)))
SELECT @location = LTRIM(RTRIM(@location))
SELECT @local_machine_name = UPPER(CONVERT(NVARCHAR(30), SERVERPROPERTY('ServerName')))
-- Turn [nullable] empty string parameters into NULLs
IF (@location = N'') SELECT @location = NULL
SELECT @retval = 0
-- Get the values that we'll need for the [re]enlistment operation (except the local time
-- which we get right before we call xp_msx_enlist to that it's as accurate as possible)
SELECT @nt_user = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))
EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
N'SYSTEM\CurrentControlSet\Control\TimeZoneInformation',
N'Bias',
@time_zone_adjustment OUTPUT,
N'no_output'
IF ((PLATFORM() & 0x1) = 0x1) -- NT
SELECT @time_zone_adjustment = -ISNULL(@time_zone_adjustment, 0)
ELSE
SELECT @time_zone_adjustment = -CONVERT(INT, CONVERT(BINARY(2), ISNULL(@time_zone_adjustment, 0)))
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXPollInterval',
@poll_interval OUTPUT,
N'no_output'
SELECT @poll_interval = ISNULL(@poll_interval, 60) -- This should be the same as DEF_REG_MSX_POLL_INTERVAL
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServerName',
@current_msx_server OUTPUT,
N'no_output'
SELECT @current_msx_server = LTRIM(RTRIM(@current_msx_server))
-- Check if this machine is an MSX (and therefore cannot be enlisted into another MSX)
IF (EXISTS (SELECT *
FROM msdb.dbo.systargetservers))
BEGIN
--Get local server/instance name
RAISERROR(14299, -1, -1, @local_machine_name)
RETURN(1) -- Failure
END
-- Check if the MSX supplied is the same as the local machine (this is not allowed)
IF (UPPER(@local_machine_name) = @msx_server_name)
BEGIN
RAISERROR(14297, -1, -1)
RETURN(1) -- Failure
END
-- Check if MSDB has be re-installed since we enlisted
IF (@current_msx_server IS NOT NULL) AND
(NOT EXISTS (SELECT *
FROM msdb.dbo.sqlagent_info
WHERE (attribute = 'DateEnlisted')))
BEGIN
-- User is tring to [re]enlist after a re-install, so we have to forcefully defect before
-- we can fully enlist again
EXECUTE msdb.dbo.sp_msx_defect @forced_defection = 1
SELECT @current_msx_server = NULL
END
-- Check if we are already enlisted, in which case we re-enlist
IF ((@current_msx_server IS NOT NULL) AND (@current_msx_server <> N''))
BEGIN
IF (UPPER(@current_msx_server) = @msx_server_name)
BEGIN
-- Update the [existing] enlistment
SELECT @local_time = CONVERT(NVARCHAR, GETDATE(), 112) + N' ' + CONVERT(NVARCHAR, GETDATE(), 108)
EXECUTE @retval = master.dbo.xp_msx_enlist 2, @msx_server_name, @nt_user, @location, @time_zone_adjustment, @local_time, @poll_interval
RETURN(@retval) -- 0 means success
END
ELSE
BEGIN
RAISERROR(14296, -1, -1, @current_msx_server)
RETURN(1) -- Failure
END
END
-- If we get this far then we're dealing with a new enlistment...
-- If no location is supplied, generate one (such as we can)
IF (@location IS NULL)
EXECUTE msdb.dbo.sp_generate_server_description @location OUTPUT
SELECT @local_time = CONVERT(NVARCHAR, GETDATE(), 112) + ' ' + CONVERT(NVARCHAR, GETDATE(), 108)
EXECUTE @retval = master.dbo.xp_msx_enlist 0, @msx_server_name, @nt_user, @location, @time_zone_adjustment, @local_time, @poll_interval
IF (@retval = 0)
BEGIN
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServerName',
N'REG_SZ',
@msx_server_name
IF (@current_msx_server IS NOT NULL)
RAISERROR(14228, 0, 1, @current_msx_server, @msx_server_name)
ELSE
RAISERROR(14229, 0, 1, @msx_server_name)
-- Update the sysoriginatingservers table with the msx server name. May need to clean up if it already has an msx entry
SELECT @msx_originating_server = NULL
-- Get the msx server name
SELECT @msx_originating_server = originating_server
FROM msdb.dbo.sysoriginatingservers
WHERE (master_server = 1)
IF(@msx_originating_server IS NULL)
BEGIN
-- Good. No msx server found so just add the new one
INSERT INTO msdb.dbo.sysoriginatingservers(originating_server, master_server) VALUES (@msx_server_name, 1)
END
ELSE
BEGIN
-- Found a previous entry. If it isn't the same server we need to clean up any existing msx jobs
IF(@msx_originating_server != @msx_server_name)
BEGIN
INSERT INTO msdb.dbo.sysoriginatingservers(originating_server, master_server) VALUES (@msx_server_name, 1)
-- Optimistically try and remove any msx jobs left over from the previous msx enlistment.
EXECUTE msdb.dbo.sp_delete_all_msx_jobs @msx_originating_server
-- And finally delete the old msx server record
DELETE msdb.dbo.sysoriginatingservers
WHERE (originating_server = @msx_originating_server)
AND (master_server = 1)
END
END
-- Add entry to sqlagent_info
INSERT INTO msdb.dbo.sqlagent_info (attribute, value) VALUES ('DateEnlisted', CONVERT(VARCHAR(10), GETDATE(), 112))
END
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_DELETE_TARGETSERVER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_targetserver...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_targetserver')
AND (type = 'P')))
DROP PROCEDURE sp_delete_targetserver
go
CREATE PROCEDURE sp_delete_targetserver
@server_name sysname,
@clear_downloadlist BIT = 1,
@post_defection BIT = 1
AS
BEGIN
DECLARE @server_id INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @server_name = UPPER(LTRIM(RTRIM(@server_name)))
-- Check server name
SELECT @server_id = server_id
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = @server_name)
IF (@server_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@server_name', @server_name)
RETURN(1) -- Failure
END
BEGIN TRANSACTION
IF (@clear_downloadlist = 1)
BEGIN
DELETE FROM msdb.dbo.sysdownloadlist
WHERE (target_server = @server_name)
END
IF (@post_defection = 1)
BEGIN
-- Post a defect instruction to the server
-- NOTE: We must do this BEFORE deleting the systargetservers row
EXECUTE msdb.dbo.sp_post_msx_operation 'DEFECT', 'SERVER', 0x00, @server_name
END
DELETE FROM msdb.dbo.systargetservers
WHERE (server_id = @server_id)
DELETE FROM msdb.dbo.systargetservergroupmembers
WHERE (server_id = @server_id)
DELETE FROM msdb.dbo.sysjobservers
WHERE (server_id = @server_id)
COMMIT TRANSACTION
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_ENLIST_TSX */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_enlist_tsx'
go
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'sp_enlist_tsx' AND type = 'P')
DROP PROCEDURE sp_enlist_tsx
GO
create proc sp_enlist_tsx
@Action int, -- 0 - enlist; 1 - defect; 2 - update
@ServerName sysname, -- tsx server name
@Location nvarchar(200), -- tsx server location
@TimeZoneAdjustment int, -- tsx server time zone adjustment
@LocalTime datetime, -- tsx server local time
@NTUserName nvarchar(100), -- name of the user performing the enlistment
@PollInterval int, -- polling interval
@TSX_Version int = 0 -- VersionMajor: ((@TSX_Version / 0x1000000) & 0xff)
-- VersionMinor: ((@TSX_Version / 0x10000) & 0xff)
-- Build no: (@TSX_Version & 0xFFFF)
as
begin
SET NOCOUNT ON
/* check permissions */
IF (ISNULL(IS_MEMBER(N'TargetServersRole'), 0) = 0) AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0)
begin
raiserror(15003,-1,-1, N'TargetServersRole')
return 1
end
--9.0 and above servers set this version param
if(@TSX_Version is null)
set @TSX_Version = 0
--Only check version during enlistment
if(@Action = 0 AND ((@TSX_Version / 0x1000000) & 0xff) < 9)
begin
DECLARE @majorVer int, @minorVer int, @buildNo int
SELECT @majorVer = ((@@microsoftversion / 0x1000000) & 0xff),
@minorVer = ((@@microsoftversion / 0x10000) & 0xff),
@buildNo = (@@microsoftversion & 0xfff)
raiserror(14306, -1, -1, @majorVer, @minorVer, @buildNo )
return 12
end
/* check input parameters */
if @ServerName is null
begin
raiserror(14043, -1, -1, '@ServerName')
return 2
end
select @ServerName = LTRIM(@ServerName)
select @ServerName = RTRIM(@ServerName)
if @ServerName = ''
begin
raiserror(21263, -1, -1, '@ServerName')
return 3
end
select @ServerName = UPPER(@ServerName)
if @Action <> 1 And @Action <> 2
begin
/* default action is to enlist */
select @Action = 0
end
if @Action = 0 /* enlisting */
begin
/* check input parameters */
if @NTUserName is null
begin
raiserror(14043, -1, -1, '@NTUserName')
return 4
end
select @NTUserName = LTRIM(@NTUserName)
select @NTUserName = RTRIM(@NTUserName)
if @NTUserName = ''
begin
raiserror(21263, -1, -1, '@NTUserName')
return 5
end
/* check if local server is already configured as TSX machine */
declare @msx_server_name sysname
select @msx_server_name = N''
execute master.dbo.xp_instance_regread
N'HKEY_LOCAL_MACHINE',
N'Software\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServerName',
@msx_server_name OUTPUT
select @msx_server_name = LTRIM(@msx_server_name)
select @msx_server_name = RTRIM(@msx_server_name)
if @msx_server_name <> N''
begin
raiserror(14360, -1, -1, @@SERVERNAME)
return 6
end
/*
* check that local server is not running a desktop SKU,
* i.e. Win9x, Office, or MSDE
*/
if( PLATFORM() & 0x100 = 0x100 )
begin
raiserror(14362, -1, -1)
return 8
end
/* check if we have any MSXOperators defined */
if not exists (SELECT * FROM msdb.dbo.sysoperators WHERE name = N'MSXOperator')
begin
raiserror(14363, -1, -1)
return 9
end
/* all checks have passed, insert new row into systargetservers table */
INSERT INTO msdb.dbo.systargetservers
(
server_name,
location,
time_zone_adjustment,
enlist_date,
last_poll_date,
status,
local_time_at_last_poll,
enlisted_by_nt_user,
poll_interval
)
VALUES
(
@ServerName,
@Location,
@TimeZoneAdjustment,
GETDATE(),
GETDATE(),
1,
@LocalTime,
@NTUserName,
@PollInterval
)
/* delete hanging rows from sysdownloadlist */
DELETE FROM msdb.dbo.sysdownloadlist
WHERE target_server = @ServerName
end
if @Action = 2 /* updating existing enlistment */
begin
/* check if we have any MSXOperators defined */
if not exists (SELECT * FROM msdb.dbo.sysoperators WHERE name = N'MSXOperator')
begin
raiserror(14363, -1, -1)
return 10
end
/* check if TSX machine is already enlisted */
If not exists (SELECT * FROM msdb.dbo.systargetservers WHERE UPPER(server_name) = @ServerName)
begin
raiserror(14364, -1, -1)
return 11
end
if @Location is null /* don't update the location if it is not supplied */
begin
UPDATE msdb.dbo.systargetservers SET
time_zone_adjustment = @TimeZoneAdjustment,
poll_interval = @PollInterval
WHERE (UPPER(server_name) = @ServerName)
end
else
begin
UPDATE msdb.dbo.systargetservers SET
location = @Location,
time_zone_adjustment = @TimeZoneAdjustment,
poll_interval = @PollInterval
WHERE (UPPER(server_name) = @ServerName)
end
end
if @Action = 1 /* defecting */
begin
if (exists (SELECT * FROM msdb.dbo.systargetservers WHERE UPPER(server_name) = @ServerName))
begin
execute msdb.dbo.sp_delete_targetserver
@server_name = @ServerName,
@post_defection = 0
end
else
begin
DELETE FROM msdb.dbo.sysdownloadlist
WHERE (target_server = @ServerName)
end
end
if @Action = 0 Or @Action = 2 /* enlisting or updating existing enlistment */
begin
/* select resultset to return to the caller */
SELECT
id,
name,
enabled,
email_address,
pager_address,
netsend_address,
weekday_pager_start_time,
weekday_pager_end_time,
saturday_pager_start_time,
saturday_pager_end_time,
sunday_pager_start_time,
sunday_pager_end_time,
pager_days
FROM
msdb.dbo.sysoperators WHERE (name = N'MSXOperator')
end
end
go
/**************************************************************/
/* SP_GET_SQLAGENT_PROPERTIES */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_get_sqlagent_properties...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_get_sqlagent_properties')
AND (type = 'P')))
DROP PROCEDURE sp_get_sqlagent_properties
go
CREATE PROCEDURE sp_get_sqlagent_properties
AS
BEGIN
DECLARE @auto_start INT
DECLARE @startup_account NVARCHAR(100)
DECLARE @msx_server_name sysname
-- Non-SQLDMO exposed properties
DECLARE @sqlserver_restart INT
DECLARE @jobhistory_max_rows INT
DECLARE @jobhistory_max_rows_per_job INT
DECLARE @errorlog_file NVARCHAR(255)
DECLARE @errorlogging_level INT
DECLARE @error_recipient NVARCHAR(30)
DECLARE @monitor_autostart INT
DECLARE @local_host_server sysname
DECLARE @job_shutdown_timeout INT
DECLARE @cmdexec_account VARBINARY(64)
DECLARE @regular_connections INT
DECLARE @host_login_name sysname
DECLARE @host_login_password VARBINARY(512)
DECLARE @login_timeout INT
DECLARE @idle_cpu_percent INT
DECLARE @idle_cpu_duration INT
DECLARE @oem_errorlog INT
DECLARE @email_profile NVARCHAR(64)
DECLARE @email_save_in_sent_folder INT
DECLARE @cpu_poller_enabled INT
DECLARE @alert_replace_runtime_tokens INT
SET NOCOUNT ON
-- NOTE: We return all SQLServerAgent properties at one go for performance reasons
-- Read the values from the registry
IF ((PLATFORM() & 0x1) = 0x1) -- NT
BEGIN
DECLARE @key NVARCHAR(200)
SELECT @key = N'SYSTEM\CurrentControlSet\Services\'
IF (SERVERPROPERTY('INSTANCENAME') IS NOT NULL)
SELECT @key = @key + N'SQLAgent$' + CONVERT (sysname, SERVERPROPERTY('INSTANCENAME'))
ELSE
SELECT @key = @key + N'SQLServerAgent'
EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
@key,
N'Start',
@auto_start OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_regread N'HKEY_LOCAL_MACHINE',
@key,
N'ObjectName',
@startup_account OUTPUT,
N'no_output'
END
ELSE
BEGIN
SELECT @auto_start = 3 -- Manual start
SELECT @startup_account = NULL
END
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServerName',
@msx_server_name OUTPUT,
N'no_output'
-- Non-SQLDMO exposed properties
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'RestartSQLServer',
@sqlserver_restart OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'JobHistoryMaxRows',
@jobhistory_max_rows OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'JobHistoryMaxRowsPerJob',
@jobhistory_max_rows_per_job OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'ErrorLogFile',
@errorlog_file OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'ErrorLoggingLevel',
@errorlogging_level OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'ErrorMonitor',
@error_recipient OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MonitorAutoStart',
@monitor_autostart OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'ServerHost',
@local_host_server OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'JobShutdownTimeout',
@job_shutdown_timeout OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'CmdExecAccount',
@cmdexec_account OUTPUT,
N'no_output'
SET @regular_connections = 0
SET @host_login_name = NULL
SET @host_login_password = NULL
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'LoginTimeout',
@login_timeout OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'IdleCPUPercent',
@idle_cpu_percent OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'IdleCPUDuration',
@idle_cpu_duration OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'OemErrorLog',
@oem_errorlog OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'EmailProfile',
@email_profile OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'EmailSaveSent',
@email_save_in_sent_folder OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'AlertReplaceRuntimeTokens',
@alert_replace_runtime_tokens OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'CoreEngineMask',
@cpu_poller_enabled OUTPUT,
N'no_output'
IF (@cpu_poller_enabled IS NOT NULL)
SELECT @cpu_poller_enabled = CASE WHEN (@cpu_poller_enabled & 32) = 32 THEN 0 ELSE 1 END
-- Return the values to the client
SELECT auto_start = CASE @auto_start
WHEN 2 THEN 1 -- 2 means auto-start
WHEN 3 THEN 0 -- 3 means don't auto-start
ELSE 0 -- Safety net
END,
msx_server_name = @msx_server_name,
sqlagent_type = (SELECT CASE
WHEN (COUNT(*) = 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) = 0) THEN 1 -- Standalone
WHEN (COUNT(*) = 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) > 0) THEN 2 -- TSX
WHEN (COUNT(*) > 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) = 0) THEN 3 -- MSX
WHEN (COUNT(*) > 0) AND (ISNULL(DATALENGTH(@msx_server_name), 0) > 0) THEN 0 -- Multi-Level MSX (currently invalid)
ELSE 0 -- Invalid
END
FROM msdb.dbo.systargetservers),
startup_account = @startup_account,
-- Non-SQLDMO exposed properties
sqlserver_restart = ISNULL(@sqlserver_restart, 1),
jobhistory_max_rows = @jobhistory_max_rows,
jobhistory_max_rows_per_job = @jobhistory_max_rows_per_job,
errorlog_file = @errorlog_file,
errorlogging_level = ISNULL(@errorlogging_level, 7),
error_recipient = @error_recipient,
monitor_autostart = ISNULL(@monitor_autostart, 0),
local_host_server = @local_host_server,
job_shutdown_timeout = ISNULL(@job_shutdown_timeout, 15),
cmdexec_account = @cmdexec_account,
regular_connections = ISNULL(@regular_connections, 0),
host_login_name = @host_login_name,
host_login_password = @host_login_password,
login_timeout = ISNULL(@login_timeout, 30),
idle_cpu_percent = ISNULL(@idle_cpu_percent, 10),
idle_cpu_duration = ISNULL(@idle_cpu_duration, 600),
oem_errorlog = ISNULL(@oem_errorlog, 0),
sysadmin_only = NULL,
email_profile = @email_profile,
email_save_in_sent_folder = ISNULL(@email_save_in_sent_folder, 0),
cpu_poller_enabled = ISNULL(@cpu_poller_enabled, 0),
alert_replace_runtime_tokens = ISNULL(@alert_replace_runtime_tokens, 0)
END
go
/**************************************************************/
/* SP_SET_SQLAGENT_PROPERTIES */
/**************************************************************/
IF EXISTS (SELECT * FROM msdb.dbo.sysobjects WHERE name = N'sp_set_sqlagent_properties' AND type = 'P')
BEGIN
DROP PROCEDURE dbo.sp_set_sqlagent_properties
END
go
PRINT ''
PRINT 'Create procedure sp_set_sqlagent_properties...'
go
CREATE PROCEDURE dbo.sp_set_sqlagent_properties
@auto_start INT = NULL, -- 1 or 0
-- Non-SQLDMO exposed properties
@sqlserver_restart INT = NULL, -- 1 or 0
@jobhistory_max_rows INT = NULL, -- No maximum = -1, otherwise must be > 1
@jobhistory_max_rows_per_job INT = NULL, -- 1 to @jobhistory_max_rows
@errorlog_file NVARCHAR(255) = NULL, -- Full drive\path\name of errorlog file
@errorlogging_level INT = NULL, -- 1 = error, 2 = warning, 4 = information
@error_recipient NVARCHAR(30) = NULL, -- Network address of error popup recipient
@monitor_autostart INT = NULL, -- 1 or 0
@local_host_server sysname = NULL, -- Alias of local host server
@job_shutdown_timeout INT = NULL, -- 5 to 600 seconds
@cmdexec_account VARBINARY(64) = NULL, -- CmdExec account information
@regular_connections INT = NULL, -- obsolete
@host_login_name sysname = NULL, -- obsolete
@host_login_password VARBINARY(512) = NULL, -- obsolete
@login_timeout INT = NULL, -- 5 to 45 (seconds)
@idle_cpu_percent INT = NULL, -- 1 to 100
@idle_cpu_duration INT = NULL, -- 20 to 86400 seconds
@oem_errorlog INT = NULL, -- 1 or 0
@sysadmin_only INT = NULL, -- not applicable to Yukon server, for backwards compatibility only
@email_profile NVARCHAR(64) = NULL, -- Email profile name
@email_save_in_sent_folder INT = NULL, -- 1 or 0
@cpu_poller_enabled INT = NULL, -- 1 or 0
@alert_replace_runtime_tokens INT = NULL, -- 1 or 0
@use_databasemail INT = NULL, -- 1 or 0
@databasemail_profile SYSNAME = NULL
AS
BEGIN
-- NOTE: We set all SQLServerAgent properties at one go for performance reasons.
-- NOTE: You cannot set the value of the properties msx_server_name, is_msx or
-- startup_account - they are all read only.
DECLARE @res_valid_range NVARCHAR(100)
DECLARE @existing_core_engine_mask INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @errorlog_file = LTRIM(RTRIM(@errorlog_file))
SELECT @error_recipient = LTRIM(RTRIM(@error_recipient))
SELECT @local_host_server = LTRIM(RTRIM(@local_host_server))
SELECT @host_login_name = LTRIM(RTRIM(@host_login_name))
SELECT @email_profile = LTRIM(RTRIM(@email_profile))
-- Make sure values (if supplied) are good
IF (@auto_start IS NOT NULL)
BEGIN
-- NOTE: When setting the the services start value, 2 == auto-start, 3 == Don't auto-start
SELECT @auto_start = CASE @auto_start
WHEN 0 THEN 3
WHEN 1 THEN 2
ELSE 3 -- Assume non auto-start if passed a junk value
END
END
-- Non-SQLDMO exposed properties
IF ((@sqlserver_restart IS NOT NULL) AND (@sqlserver_restart <> 0))
SELECT @sqlserver_restart = 1
IF (@jobhistory_max_rows IS NOT NULL)
BEGIN
SELECT @res_valid_range = FORMATMESSAGE(14207)
IF ((@jobhistory_max_rows < -1) OR (@jobhistory_max_rows = 0))
BEGIN
RAISERROR(14266, -1, -1, '@jobhistory_max_rows', @res_valid_range)
RETURN(1) -- Failure
END
END
ELSE
BEGIN
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'JobHistoryMaxRows',
@jobhistory_max_rows OUTPUT,
N'no_output'
SELECT @jobhistory_max_rows = ISNULL(@jobhistory_max_rows, -1)
END
IF (@jobhistory_max_rows_per_job IS NOT NULL)
BEGIN
IF (@jobhistory_max_rows = -1)
SELECT @jobhistory_max_rows_per_job = 0
ELSE
BEGIN
IF ((@jobhistory_max_rows_per_job < 1) OR (@jobhistory_max_rows_per_job > @jobhistory_max_rows))
BEGIN
SELECT @res_valid_range = N'1..' + CONVERT(NVARCHAR, @jobhistory_max_rows)
RAISERROR(14266, -1, -1, '@jobhistory_max_rows', @res_valid_range)
RETURN(1) -- Failure
END
END
END
IF (@errorlogging_level IS NOT NULL) AND ((@errorlogging_level < 1) OR (@errorlogging_level > 7))
BEGIN
RAISERROR(14266, -1, -1, '@errorlogging_level', '1..7')
RETURN(1) -- Failure
END
IF (@monitor_autostart IS NOT NULL) AND ((@monitor_autostart < 0) OR (@monitor_autostart > 1))
BEGIN
RAISERROR(14266, -1, -1, '@monitor_autostart', '0, 1')
RETURN(1) -- Failure
END
IF (@job_shutdown_timeout IS NOT NULL) AND ((@job_shutdown_timeout < 5) OR (@job_shutdown_timeout > 600))
BEGIN
RAISERROR(14266, -1, -1, '@job_shutdown_timeout', '5..600')
RETURN(1) -- Failure
END
IF (@login_timeout IS NOT NULL) AND ((@login_timeout < 5) OR (@login_timeout > 45))
BEGIN
RAISERROR(14266, -1, -1, '@login_timeout', '5..45')
RETURN(1) -- Failure
END
IF ((@idle_cpu_percent IS NOT NULL) AND ((@idle_cpu_percent < 1) OR (@idle_cpu_percent > 100)))
BEGIN
RAISERROR(14266, -1, -1, '@idle_cpu_percent', '10..100')
RETURN(1) -- Failure
END
IF ((@idle_cpu_duration IS NOT NULL) AND ((@idle_cpu_duration < 20) OR (@idle_cpu_duration > 86400)))
BEGIN
RAISERROR(14266, -1, -1, '@idle_cpu_duration', '20..86400')
RETURN(1) -- Failure
END
IF (@oem_errorlog IS NOT NULL) AND ((@oem_errorlog < 0) OR (@oem_errorlog > 1))
BEGIN
RAISERROR(14266, -1, -1, '@oem_errorlog', '0, 1')
RETURN(1) -- Failure
END
IF (@sysadmin_only IS NOT NULL)
BEGIN
RAISERROR(14378, -1, -1)
RETURN(1) -- Failure
END
IF (@email_save_in_sent_folder IS NOT NULL) AND ((@email_save_in_sent_folder < 0) OR (@email_save_in_sent_folder > 1))
BEGIN
RAISERROR(14266, -1, -1, 'email_save_in_sent_folder', '0, 1')
RETURN(1) -- Failure
END
IF (@cpu_poller_enabled IS NOT NULL) AND ((@cpu_poller_enabled < 0) OR (@cpu_poller_enabled > 1))
BEGIN
RAISERROR(14266, -1, -1, 'cpu_poller_enabled', '0, 1')
RETURN(1) -- Failure
END
IF (@alert_replace_runtime_tokens IS NOT NULL) AND ((@alert_replace_runtime_tokens < 0) OR (@alert_replace_runtime_tokens > 1))
BEGIN
RAISERROR(14266, -1, -1, 'alert_replace_runtime_tokens', '0, 1')
RETURN(1) -- Failure
END
-- Write out the values
IF (@auto_start IS NOT NULL)
BEGIN
IF ((PLATFORM() & 0x1) = 0x1) -- NT
BEGIN
DECLARE @key NVARCHAR(200)
SELECT @key = N'SYSTEM\CurrentControlSet\Services\'
IF (SERVERPROPERTY('INSTANCENAME') IS NOT NULL)
SELECT @key = @key + N'SQLAgent$' + CONVERT (sysname, SERVERPROPERTY('INSTANCENAME'))
ELSE
SELECT @key = @key + N'SQLServerAgent'
EXECUTE master.dbo.xp_regwrite N'HKEY_LOCAL_MACHINE',
@key,
N'Start',
N'REG_DWORD',
@auto_start
END
ELSE
RAISERROR(14546, 16, 1, '@auto_start')
END
-- Non-SQLDMO exposed properties
IF (@sqlserver_restart IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'RestartSQLServer',
N'REG_DWORD',
@sqlserver_restart
IF (@jobhistory_max_rows IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'JobHistoryMaxRows',
N'REG_DWORD',
@jobhistory_max_rows
IF (@jobhistory_max_rows_per_job IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'JobHistoryMaxRowsPerJob',
N'REG_DWORD',
@jobhistory_max_rows_per_job
IF (@errorlog_file IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'ErrorLogFile',
N'REG_SZ',
@errorlog_file
IF (@errorlogging_level IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'ErrorLoggingLevel',
N'REG_DWORD',
@errorlogging_level
IF (@error_recipient IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'ErrorMonitor',
N'REG_SZ',
@error_recipient
IF (@monitor_autostart IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MonitorAutoStart',
N'REG_DWORD',
@monitor_autostart
IF (@local_host_server IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'ServerHost',
N'REG_SZ',
@local_host_server
IF (@job_shutdown_timeout IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'JobShutdownTimeout',
N'REG_DWORD',
@job_shutdown_timeout
IF (@cmdexec_account IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'CmdExecAccount',
N'REG_BINARY',
@cmdexec_account
IF (@login_timeout IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'LoginTimeout',
N'REG_DWORD',
@login_timeout
IF (@idle_cpu_percent IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'IdleCPUPercent',
N'REG_DWORD',
@idle_cpu_percent
IF (@idle_cpu_duration IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'IdleCPUDuration',
N'REG_DWORD',
@idle_cpu_duration
IF (@oem_errorlog IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'OemErrorLog',
N'REG_DWORD',
@oem_errorlog
IF (@email_profile IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'EmailProfile',
N'REG_SZ',
@email_profile
IF (@email_save_in_sent_folder IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'EmailSaveSent',
N'REG_DWORD',
@email_save_in_sent_folder
IF (@alert_replace_runtime_tokens IS NOT NULL)
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'AlertReplaceRuntimeTokens',
N'REG_DWORD',
@alert_replace_runtime_tokens
IF (@cpu_poller_enabled IS NOT NULL)
BEGIN
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'CoreEngineMask',
@existing_core_engine_mask OUTPUT,
N'no_output'
IF ((@existing_core_engine_mask IS NOT NULL) OR (@cpu_poller_enabled = 1))
BEGIN
IF (@cpu_poller_enabled = 1)
SELECT @cpu_poller_enabled = (ISNULL(@existing_core_engine_mask, 0) & ~32)
ELSE
SELECT @cpu_poller_enabled = (ISNULL(@existing_core_engine_mask, 0) | 32)
IF ((@existing_core_engine_mask IS NOT NULL) AND (@cpu_poller_enabled = 32))
EXECUTE master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'CoreEngineMask'
ELSE
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'CoreEngineMask',
N'REG_DWORD',
@cpu_poller_enabled
END
END
DECLARE @notify_sqlagent_dbmail_settings_update BIT
SET @notify_sqlagent_dbmail_settings_update = 0
IF(@use_databasemail IS NOT NULL)
BEGIN
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'UseDatabaseMail',
N'REG_DWORD',
@use_databasemail
SET @notify_sqlagent_dbmail_settings_update = 1
END
IF(@databasemail_profile IS NOT NULL)
BEGIN
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'DatabaseMailProfile',
N'REG_SZ',
@databasemail_profile
SET @notify_sqlagent_dbmail_settings_update = 1
END
IF(@notify_sqlagent_dbmail_settings_update = 1 )
BEGIN
-- Notify SQL Agent that Databasemail settings for SQL Agent was changed. force a reload
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'M'
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_ADD_TARGETSERVERGROUP */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_targetservergroup...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_targetservergroup')
AND (type = 'P')))
DROP PROCEDURE sp_add_targetservergroup
go
CREATE PROCEDURE sp_add_targetservergroup
@name sysname
AS
BEGIN
SET NOCOUNT ON
-- Only a sysadmin can do this
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
-- Check if the group already exists
IF (EXISTS (SELECT *
FROM msdb.dbo.systargetservergroups
WHERE name = @name))
BEGIN
RAISERROR(14261, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
-- Disallow names with commas in them (since sp_apply_job_to_targets parses a comma-separated list of group names)
IF (@name LIKE N'%,%')
BEGIN
RAISERROR(14289, -1, -1, '@name', ',')
RETURN(1) -- Failure
END
INSERT INTO msdb.dbo.systargetservergroups (name)
VALUES (@name)
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_UPDATE_TARGETSERVERGROUP */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_targetservergroup...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_update_targetservergroup')
AND (type = 'P')))
DROP PROCEDURE sp_update_targetservergroup
go
CREATE PROCEDURE sp_update_targetservergroup
@name sysname,
@new_name sysname
AS
BEGIN
SET NOCOUNT ON
-- Only a sysadmin can do this
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
SELECT @new_name = LTRIM(RTRIM(@new_name))
-- Check if the group exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.systargetservergroups
WHERE (name = @name)))
BEGIN
RAISERROR(14262, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
-- Check if a group with the new name already exists
IF (EXISTS (SELECT *
FROM msdb.dbo.systargetservergroups
WHERE (name = @new_name)))
BEGIN
RAISERROR(14261, -1, -1, '@new_name', @new_name)
RETURN(1) -- Failure
END
-- Disallow names with commas in them (since sp_apply_job_to_targets parses a comma-separated list of group names)
IF (@new_name LIKE N'%,%')
BEGIN
RAISERROR(14289, -1, -1, '@new_name', ',')
RETURN(1) -- Failure
END
-- Update the group's name
UPDATE msdb.dbo.systargetservergroups
SET name = @new_name
WHERE (name = @name)
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_DELETE_TARGETSERVERGROUP */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_targetservergroup...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_targetservergroup')
AND (type = 'P')))
DROP PROCEDURE sp_delete_targetservergroup
go
CREATE PROCEDURE sp_delete_targetservergroup
@name sysname
AS
BEGIN
DECLARE @servergroup_id INT
SET NOCOUNT ON
-- Only a sysadmin can do this
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
-- Check if the group exists
SELECT @servergroup_id = servergroup_id
FROM msdb.dbo.systargetservergroups
WHERE (name = @name)
IF (@servergroup_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
-- Remove the group members
DELETE FROM msdb.dbo.systargetservergroupmembers
WHERE (servergroup_id = @servergroup_id)
-- Remove the group
DELETE FROM msdb.dbo.systargetservergroups
WHERE (name = @name)
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_HELP_TARGETSERVERGROUP */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_targetservergroup...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_targetservergroup')
AND (type = 'P')))
DROP PROCEDURE sp_help_targetservergroup
go
CREATE PROCEDURE sp_help_targetservergroup
@name sysname = NULL
AS
BEGIN
DECLARE @servergroup_id INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
IF (@name IS NULL)
BEGIN
-- Show all groups
SELECT servergroup_id, name
FROM msdb.dbo.systargetservergroups
RETURN(@@error) -- 0 means success
END
ELSE
BEGIN
-- Check if the group exists
SELECT @servergroup_id = servergroup_id
FROM msdb.dbo.systargetservergroups
WHERE (name = @name)
IF (@servergroup_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
-- Return the members of the group
SELECT sts.server_id,
sts.server_name
FROM msdb.dbo.systargetservers sts,
msdb.dbo.systargetservergroupmembers stsgm
WHERE (stsgm.servergroup_id = @servergroup_id)
AND (stsgm.server_id = sts.server_id)
RETURN(@@error) -- 0 means success
END
END
go
/**************************************************************/
/* SP_ADD_TARGETSVRGRP_MEMBER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_targetsvgrp_member...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_targetsvrgrp_member')
AND (type = 'P')))
DROP PROCEDURE sp_add_targetsvrgrp_member
go
CREATE PROCEDURE sp_add_targetsvrgrp_member
@group_name sysname,
@server_name sysname
AS
BEGIN
DECLARE @servergroup_id INT
DECLARE @server_id INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @group_name = LTRIM(RTRIM(@group_name))
SELECT @server_name = UPPER(LTRIM(RTRIM(@server_name)))
-- Check if the group exists
SELECT @servergroup_id = servergroup_id
FROM msdb.dbo.systargetservergroups
WHERE (name = @group_name)
IF (@servergroup_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@group_name', @group_name)
RETURN(1) -- Failure
END
-- Check if the server exists
SELECT @server_id = server_id
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = @server_name)
IF (@server_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@server_name', @server_name)
RETURN(1) -- Failure
END
-- Check if the server is already in this group
IF (EXISTS (SELECT *
FROM msdb.dbo.systargetservergroupmembers
WHERE (servergroup_id = @servergroup_id)
AND (server_id = @server_id)))
BEGIN
RAISERROR(14263, -1, -1, @server_name, @group_name)
RETURN(1) -- Failure
END
-- Add the row to systargetservergroupmembers
INSERT INTO msdb.dbo.systargetservergroupmembers
VALUES (@servergroup_id, @server_id)
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_DELETE_TARGETSVRGRP_MEMBER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_targetsvrgrp_member...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_targetsvrgrp_member')
AND (type = 'P')))
DROP PROCEDURE sp_delete_targetsvrgrp_member
go
CREATE PROCEDURE sp_delete_targetsvrgrp_member
@group_name sysname,
@server_name sysname
AS
BEGIN
DECLARE @servergroup_id INT
DECLARE @server_id INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @group_name = LTRIM(RTRIM(@group_name))
SELECT @server_name = UPPER(LTRIM(RTRIM(@server_name)))
-- Check if the group exists
SELECT @servergroup_id = servergroup_id
FROM msdb.dbo.systargetservergroups
WHERE (name = @group_name)
IF (@servergroup_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@group_name', @group_name)
RETURN(1) -- Failure
END
-- Check if the server exists
SELECT @server_id = server_id
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = @server_name)
IF (@server_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@server_name', @server_name)
RETURN(1) -- Failure
END
-- Check if the server is in the group
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.systargetservergroupmembers
WHERE (servergroup_id = @servergroup_id)
AND (server_id = @server_id)))
BEGIN
RAISERROR(14264, -1, -1, @server_name, @group_name)
RETURN(1) -- Failure
END
-- Delete the row from systargetservergroupmembers
DELETE FROM msdb.dbo.systargetservergroupmembers
WHERE (servergroup_id = @servergroup_id)
AND (server_id = @server_id)
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_VERIFY_CATEGORY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_category...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_category')
AND (type = 'P')))
DROP PROCEDURE sp_verify_category
go
CREATE PROCEDURE sp_verify_category
@class VARCHAR(8),
@type VARCHAR(12) = NULL, -- Supply NULL only if you don't want it checked
@name sysname = NULL, -- Supply NULL only if you don't want it checked
@category_class INT OUTPUT,
@category_type INT OUTPUT -- Supply NULL only if you don't want the return value
AS
BEGIN
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @class = LTRIM(RTRIM(@class))
SELECT @type = LTRIM(RTRIM(@type))
SELECT @name = LTRIM(RTRIM(@name))
-- Turn [nullable] empty string parameters into NULLs
IF (@type = '') SELECT @type = NULL
IF (@name = N'') SELECT @name = NULL
-- Check class
SELECT @class = UPPER(@class collate SQL_Latin1_General_CP1_CS_AS)
SELECT @category_class = CASE @class
WHEN 'JOB' THEN 1
WHEN 'ALERT' THEN 2
WHEN 'OPERATOR' THEN 3
ELSE 0
END
IF (@category_class = 0)
BEGIN
RAISERROR(14266, -1, -1, '@class', 'JOB, ALERT, OPERATOR')
RETURN(1) -- Failure
END
-- Check name
IF ((@name IS NOT NULL) AND (@name = N'[DEFAULT]'))
BEGIN
RAISERROR(14200, -1, -1, '@name')
RETURN(1) -- Failure
END
-- Check type [optionally]
IF (@type IS NOT NULL)
BEGIN
IF (@class = 'JOB')
BEGIN
SELECT @type = UPPER(@type collate SQL_Latin1_General_CP1_CS_AS)
SELECT @category_type = CASE @type
WHEN 'LOCAL' THEN 1
WHEN 'MULTI-SERVER' THEN 2
ELSE 0
END
IF (@category_type = 0)
BEGIN
RAISERROR(14266, -1, -1, '@type', 'LOCAL, MULTI-SERVER')
RETURN(1) -- Failure
END
END
ELSE
BEGIN
IF (@type <> 'NONE')
BEGIN
RAISERROR(14266, -1, -1, '@type', 'NONE')
RETURN(1) -- Failure
END
ELSE
SELECT @category_type = 3
END
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_ADD_CATEGORY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_category...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_category')
AND (type = 'P')))
DROP PROCEDURE sp_add_category
go
CREATE PROCEDURE sp_add_category
@class VARCHAR(8) = 'JOB', -- JOB or ALERT or OPERATOR
@type VARCHAR(12) = 'LOCAL', -- LOCAL or MULTI-SERVER (for JOB) or NONE otherwise
@name sysname
AS
BEGIN
DECLARE @retval INT
DECLARE @category_type INT
DECLARE @category_class INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @class = LTRIM(RTRIM(@class))
SELECT @type = LTRIM(RTRIM(@type))
SELECT @name = LTRIM(RTRIM(@name))
EXECUTE @retval = sp_verify_category @class,
@type,
@name,
@category_class OUTPUT,
@category_type OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check name
IF (EXISTS (SELECT *
FROM msdb.dbo.syscategories
WHERE (category_class = @category_class)
AND (name = @name)))
BEGIN
RAISERROR(14261, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
-- Add the row
INSERT INTO msdb.dbo.syscategories (category_class, category_type, name)
VALUES (@category_class, @category_type, @name)
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_UPDATE_CATEGORY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_category...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_update_category')
AND (type = 'P')))
DROP PROCEDURE sp_update_category
go
CREATE PROCEDURE sp_update_category
@class VARCHAR(8), -- JOB or ALERT or OPERATOR
@name sysname,
@new_name sysname
AS
BEGIN
DECLARE @retval INT
DECLARE @category_id INT
DECLARE @category_class INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @class = LTRIM(RTRIM(@class))
SELECT @name = LTRIM(RTRIM(@name))
SELECT @new_name = LTRIM(RTRIM(@new_name))
--turn empy parametrs tu null parameters
IF @name = '' SELECT @name = NULL
EXECUTE @retval = sp_verify_category @class,
NULL,
@new_name,
@category_class OUTPUT,
NULL
IF (@retval <> 0)
RETURN(1) -- Failure
--ID @name not null check id such a category exists
--check name - it should exist if not null
IF @name IS NOT NULL AND
NOT EXISTS(SELECT * FROM msdb.dbo.syscategories WHERE name = @name
AND category_class = @category_class)
BEGIN
RAISERROR(14526, -1, -1, @name, @category_class)
RETURN(1) -- Failure
END
-- Check name
SELECT @category_id = category_id
FROM msdb.dbo.syscategories
WHERE (category_class = @category_class)
AND (name = @new_name)
IF (@category_id IS NOT NULL)
BEGIN
RAISERROR(14261, -1, -1, '@new_name', @new_name)
RETURN(1) -- Failure
END
-- Make sure that we're not updating one of the permanent categories (id's 0 - 99)
IF (@category_id < 100)
BEGIN
RAISERROR(14276, -1, -1, @name, @class)
RETURN(1) -- Failure
END
-- Update the category name
UPDATE msdb.dbo.syscategories
SET name = @new_name
WHERE (category_class = @category_class)
AND (name = @name)
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_DELETE_CATEGORY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_category...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_category')
AND (type = 'P')))
DROP PROCEDURE sp_delete_category
go
CREATE PROCEDURE sp_delete_category
@class VARCHAR(8), -- JOB or ALERT or OPERATOR
@name sysname
AS
BEGIN
DECLARE @retval INT
DECLARE @category_id INT
DECLARE @category_class INT
DECLARE @category_type INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @class = LTRIM(RTRIM(@class))
SELECT @name = LTRIM(RTRIM(@name))
EXECUTE @retval = sp_verify_category @class,
NULL,
NULL,
@category_class OUTPUT,
NULL
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check name
SELECT @category_id = category_id,
@category_type = category_type
FROM msdb.dbo.syscategories
WHERE (category_class = @category_class)
AND (name = @name)
IF (@category_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
-- Make sure that we're not deleting one of the permanent categories (id's 0 - 99)
IF (@category_id < 100)
BEGIN
RAISERROR(14276, -1, -1, @name, @class)
RETURN(1) -- Failure
END
BEGIN TRANSACTION
-- Clean-up any Jobs that reference the deleted category
UPDATE msdb.dbo.sysjobs
SET category_id = CASE @category_type
WHEN 1 THEN 0 -- [Uncategorized (Local)]
WHEN 2 THEN 2 -- [Uncategorized (Multi-Server)]
END
WHERE (category_id = @category_id)
-- Clean-up any Alerts that reference the deleted category
UPDATE msdb.dbo.sysalerts
SET category_id = 98
WHERE (category_id = @category_id)
-- Clean-up any Operators that reference the deleted category
UPDATE msdb.dbo.sysoperators
SET category_id = 99
WHERE (category_id = @category_id)
-- Finally, delete the category itself
DELETE FROM msdb.dbo.syscategories
WHERE (category_id = @category_id)
COMMIT TRANSACTION
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_HELP_CATEGORY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_category...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_category')
AND (type = 'P')))
DROP PROCEDURE sp_help_category
go
CREATE PROCEDURE sp_help_category
@class VARCHAR(8) = 'JOB', -- JOB, ALERT or OPERATOR
@type VARCHAR(12) = NULL, -- LOCAL, MULTI-SERVER, or NONE
@name sysname = NULL,
@suffix BIT = 0 -- 0 = no suffix, 1 = add suffix
AS
BEGIN
DECLARE @retval INT
DECLARE @type_in VARCHAR(12)
DECLARE @category_type INT
DECLARE @category_class INT
DECLARE @where_clause NVARCHAR(500)
DECLARE @cmd NVARCHAR(max)
SET NOCOUNT ON
-- Both name and type can be NULL (this is valid, indeed it is how SQLDMO populates
-- the JobCategory collection)
-- Remove any leading/trailing spaces from parameters
SELECT @class = LTRIM(RTRIM(@class))
SELECT @type = LTRIM(RTRIM(@type))
SELECT @name = LTRIM(RTRIM(@name))
-- Turn [nullable] empty string parameters into NULLs
IF (@type = '') SELECT @type = NULL
IF (@name = N'') SELECT @name = NULL
-- Check the type and class
IF (@class = 'JOB') AND (@type IS NULL)
SELECT @type_in = 'LOCAL' -- This prevents sp_verify_category from failing
ELSE
IF (@class <> 'JOB') AND (@type IS NULL)
SELECT @type_in = 'NONE'
ELSE
SELECT @type_in = @type
EXECUTE @retval = sp_verify_category @class,
@type_in,
NULL,
@category_class OUTPUT,
@category_type OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Make sure that 'suffix' is either 0 or 1
IF (@suffix <> 0)
SELECT @suffix = 1
--check name - it should exist if not null
IF @name IS NOT NULL AND
NOT EXISTS(SELECT * FROM msdb.dbo.syscategories WHERE name = @name
AND category_class = @category_class)
BEGIN
DECLARE @category_class_string NVARCHAR(25)
SET @category_class_string = CAST(@category_class AS nvarchar(25))
RAISERROR(14526, -1, -1, @name, @category_class_string)
RETURN(1) -- Failure
END
-- Build the WHERE qualifier
SELECT @where_clause = N'WHERE (category_class = ' + CONVERT(NVARCHAR, @category_class) + N') '
IF (@name IS NOT NULL)
SELECT @where_clause = @where_clause + N'AND (name = N' + QUOTENAME(@name, '''') + N') '
IF (@type IS NOT NULL)
SELECT @where_clause = @where_clause + N'AND (category_type = ' + CONVERT(NVARCHAR, @category_type) + N') '
-- Construct the query
SELECT @cmd = N'SELECT category_id, '
IF (@suffix = 1)
BEGIN
SELECT @cmd = @cmd + N'''category_type'' = '
SELECT @cmd = @cmd + N'CASE category_type '
SELECT @cmd = @cmd + N'WHEN 0 THEN ''NONE'' '
SELECT @cmd = @cmd + N'WHEN 1 THEN ''LOCAL'' '
SELECT @cmd = @cmd + N'WHEN 2 THEN ''MULTI-SERVER'' '
SELECT @cmd = @cmd + N'WHEN 3 THEN ''NONE'' '
SELECT @cmd = @cmd + N'ELSE FORMATMESSAGE(14205) '
SELECT @cmd = @cmd + N'END, '
END
ELSE
BEGIN
SELECT @cmd = @cmd + N'category_type, '
END
SELECT @cmd = @cmd + N'name '
SELECT @cmd = @cmd + N'FROM msdb.dbo.syscategories '
-- Execute the query
EXECUTE (@cmd + @where_clause + N'ORDER BY category_type, name')
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_HELP_TARGETSERVER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_targetserver...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_targetserver')
AND (type = 'P')))
DROP PROCEDURE sp_help_targetserver
go
CREATE PROCEDURE sp_help_targetserver
@server_name sysname = NULL
AS
BEGIN
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @server_name = UPPER(LTRIM(RTRIM(@server_name)))
IF (@server_name IS NOT NULL)
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = @server_name)))
BEGIN
RAISERROR(14262, -1, -1, '@server_name', @server_name)
RETURN(1) -- Failure
END
END
DECLARE @unread_instructions TABLE
(
target_server sysname COLLATE database_default,
unread_instructions INT
)
INSERT INTO @unread_instructions
SELECT target_server, COUNT(*)
FROM msdb.dbo.sysdownloadlist
WHERE (status = 0)
GROUP BY target_server
SELECT sts.server_id,
sts.server_name,
sts.location,
sts.time_zone_adjustment,
sts.enlist_date,
sts.last_poll_date,
'status' = sts.status |
CASE WHEN DATEDIFF(ss, sts.last_poll_date, GETDATE()) > (3 * sts.poll_interval) THEN 0x2 ELSE 0 END |
CASE WHEN ((SELECT COUNT(*)
FROM msdb.dbo.sysdownloadlist sdl
WHERE (sdl.target_server = sts.server_name)
AND (sdl.error_message IS NOT NULL)) > 0) THEN 0x4 ELSE 0 END,
'unread_instructions' = ISNULL(ui.unread_instructions, 0),
'local_time' = DATEADD(SS, DATEDIFF(SS, sts.last_poll_date, GETDATE()), sts.local_time_at_last_poll),
sts.enlisted_by_nt_user,
sts.poll_interval
FROM msdb.dbo.systargetservers sts LEFT OUTER JOIN
@unread_instructions ui ON (sts.server_name = ui.target_server)
WHERE ((@server_name IS NULL) OR (UPPER(sts.server_name) = @server_name))
ORDER BY server_name
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_RESYNC_TARGETSERVER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_resync_targetserver...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_resync_targetserver')
AND (type = 'P')))
DROP PROCEDURE sp_resync_targetserver
go
CREATE PROCEDURE sp_resync_targetserver
@server_name sysname
AS
BEGIN
SET NOCOUNT ON
-- Only a sysadmin can do this
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Remove any leading/trailing spaces from parameters
SELECT @server_name = LTRIM(RTRIM(@server_name))
IF (UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) <> N'ALL')
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = UPPER(@server_name))))
BEGIN
RAISERROR(14262, -1, -1, '@server_name', @server_name)
RETURN(1) -- Failure
END
-- We want the target server to:
-- a) delete all their current MSX jobs, and
-- b) download all their jobs again.
-- So we delete all the current instructions and post a new set
DELETE FROM msdb.dbo.sysdownloadlist
WHERE (target_server = @server_name)
EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', 0x00, @server_name
EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', 0x00, @server_name
END
ELSE
BEGIN
-- We want ALL target servers to:
-- a) delete all their current MSX jobs, and
-- b) download all their jobs again.
-- So we delete all the current instructions and post a new set
TRUNCATE TABLE msdb.dbo.sysdownloadlist
EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', 0x00, NULL
EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', 0x00, NULL
END
RETURN(@@error) -- 0 means success
END
go
CHECKPOINT
go
/**************************************************************/
/* SP_PURGE_JOBHISTORY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_purge_jobhistory...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_purge_jobhistory')
AND (type = 'P')))
DROP PROCEDURE sp_purge_jobhistory
go
CREATE PROCEDURE sp_purge_jobhistory
@job_name sysname = NULL,
@job_id UNIQUEIDENTIFIER = NULL,
@oldest_date DATETIME = NULL
AS
BEGIN
DECLARE @rows_affected INT
DECLARE @total_rows INT
DECLARE @datepart INT
DECLARE @timepart INT
DECLARE @retval INT
DECLARE @job_owner_sid VARBINARY(85)
SET NOCOUNT ON
IF(@oldest_date IS NOT NULL)
BEGIN
SET @datepart = CONVERT(INT, CONVERT(VARCHAR, @oldest_date, 112))
SET @timepart = (DATEPART(hh, @oldest_date) * 10000) + (DATEPART(mi, @oldest_date) * 100) + (DATEPART(ss, @oldest_date))
END
ELSE
BEGIN
SET @datepart = 99999999
SET @timepart = 0
END
IF ((@job_name IS NOT NULL) OR (@job_id IS NOT NULL))
BEGIN
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check permissions beyond what's checked by the sysjobs_view
-- SQLAgentReader role that can see all jobs but
-- cannot purge history of jobs they do not own
IF (@job_owner_sid <> SUSER_SID() -- does not own the job
AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1) -- is not sysadmin
AND (ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) <> 1)) -- is not SQLAgentOperatorRole
BEGIN
RAISERROR(14392, -1, -1);
RETURN(1) -- Failure
END
-- Delete the histories for this job
DELETE FROM msdb.dbo.sysjobhistory
WHERE (job_id = @job_id) AND
((run_date < @datepart) OR
(run_date <= @datepart AND run_time < @timepart))
SELECT @rows_affected = @@rowcount
END
ELSE
BEGIN
-- Only a sysadmin or SQLAgentOperatorRole can do this
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1) -- is not sysadmin
AND (ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) <> 1)) -- is not SQLAgentOperatorRole
BEGIN
RAISERROR(14392, -1, -1)
RETURN(1) -- Failure
END
IF(@oldest_date IS NOT NULL)
BEGIN
DELETE FROM msdb.dbo.sysjobhistory
WHERE ((run_date < @datepart) OR
(run_date <= @datepart AND run_time < @timepart))
END
ELSE
BEGIN
DELETE FROM msdb.dbo.sysjobhistory
END
SELECT @rows_affected = @@rowcount
END
RAISERROR(14226, 0, 1, @rows_affected)
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_HELP_JOBHISTORY_FULL */
/**************************************************************/
use [msdb]
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_jobhistory_full')
AND (type = 'P')))
DROP PROCEDURE sp_help_jobhistory_full
go
CREATE PROCEDURE sp_help_jobhistory_full
@job_id UNIQUEIDENTIFIER,
@job_name sysname,
@step_id INT,
@sql_message_id INT,
@sql_severity INT,
@start_run_date INT,
@end_run_date INT,
@start_run_time INT,
@end_run_time INT,
@minimum_run_duration INT,
@run_status INT,
@minimum_retries INT,
@oldest_first INT,
@server sysname,
@mode VARCHAR(7),
@order_by INT,
@distributed_job_history BIT
AS
BEGIN
-- First save the current transaction isolation level
DECLARE @TRANSACTION_ISOLATION_LEVEL INT
SELECT @TRANSACTION_ISOLATION_LEVEL = transaction_isolation_level FROM sys.dm_exec_sessions where session_id = @@SPID
-- If the isolation level is not known, do nothing!
IF @TRANSACTION_ISOLATION_LEVEL >0 AND @TRANSACTION_ISOLATION_LEVEL < 6
BEGIN
-- Set transaction isolation level to READ UNCOMMITTED
-- This will ensure that we can still read the history even if the rows are locked by the TABLOCKX operation on the history row limiter
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
END
IF(@distributed_job_history = 1)
SELECT null as instance_id,
sj.job_id,
job_name = sj.name,
null as step_id,
null as step_name,
null as sql_message_id,
null as sql_severity,
sjh.last_outcome_message as message,
sjh.last_run_outcome as run_status,
sjh.last_run_date as run_date,
sjh.last_run_time as run_time,
sjh.last_run_duration as run_duration,
null as operator_emailed,
null as operator_netsentname,
null as operator_paged,
null as retries_attempted,
sts.server_name as server
FROM msdb.dbo.sysjobservers sjh
JOIN msdb.dbo.systargetservers sts ON (sts.server_id = sjh.server_id)
JOIN msdb.dbo.sysjobs_view sj ON(sj.job_id = sjh.job_id)
WHERE
(@job_id = sjh.job_id)
AND ((@start_run_date IS NULL) OR (sjh.last_run_date >= @start_run_date))
AND ((@end_run_date IS NULL) OR (sjh.last_run_date <= @end_run_date))
AND ((@start_run_time IS NULL) OR (sjh.last_run_time >= @start_run_time))
AND ((@minimum_run_duration IS NULL) OR (sjh.last_run_duration >= @minimum_run_duration))
AND ((@run_status IS NULL) OR (@run_status = sjh.last_run_outcome))
AND ((@server IS NULL) OR (sts.server_name = @server))
ELSE
SELECT sjh.instance_id, -- This is included just for ordering purposes
sj.job_id,
job_name = sj.name,
sjh.step_id,
sjh.step_name,
sjh.sql_message_id,
sjh.sql_severity,
sjh.message,
sjh.run_status,
sjh.run_date,
sjh.run_time,
sjh.run_duration,
operator_emailed = so1.name,
operator_netsent = so2.name,
operator_paged = so3.name,
sjh.retries_attempted,
sjh.server
FROM msdb.dbo.sysjobhistory sjh
LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjh.operator_id_emailed = so1.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjh.operator_id_netsent = so2.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjh.operator_id_paged = so3.id),
msdb.dbo.sysjobs_view sj
WHERE (sj.job_id = sjh.job_id)
AND ((@job_id IS NULL) OR (@job_id = sjh.job_id))
AND ((@step_id IS NULL) OR (@step_id = sjh.step_id))
AND ((@sql_message_id IS NULL) OR (@sql_message_id = sjh.sql_message_id))
AND ((@sql_severity IS NULL) OR (@sql_severity = sjh.sql_severity))
AND ((@start_run_date IS NULL) OR (sjh.run_date >= @start_run_date))
AND ((@end_run_date IS NULL) OR (sjh.run_date <= @end_run_date))
AND ((@start_run_time IS NULL) OR (sjh.run_time >= @start_run_time))
AND ((@end_run_time IS NULL) OR (sjh.run_time <= @end_run_time))
AND ((@minimum_run_duration IS NULL) OR (sjh.run_duration >= @minimum_run_duration))
AND ((@run_status IS NULL) OR (@run_status = sjh.run_status))
AND ((@minimum_retries IS NULL) OR (sjh.retries_attempted >= @minimum_retries))
AND ((@server IS NULL) OR (sjh.server = @server))
ORDER BY (sjh.instance_id * @order_by)
-- Revert the isolation level
IF @TRANSACTION_ISOLATION_LEVEL = 1
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
ELSE IF @TRANSACTION_ISOLATION_LEVEL = 2
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
ELSE IF @TRANSACTION_ISOLATION_LEVEL = 3
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
ELSE IF @TRANSACTION_ISOLATION_LEVEL = 4
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
ELSE IF @TRANSACTION_ISOLATION_LEVEL = 5
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
END
GO
/**************************************************************/
/* SP_HELP_JOBHISTORY_SUMMARY */
/**************************************************************/
use [msdb]
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_jobhistory_summary')
AND (type = 'P')))
DROP PROCEDURE sp_help_jobhistory_summary
go
CREATE PROCEDURE sp_help_jobhistory_summary
@job_id UNIQUEIDENTIFIER,
@job_name sysname,
@step_id INT,
@sql_message_id INT,
@sql_severity INT,
@start_run_date INT,
@end_run_date INT,
@start_run_time INT,
@end_run_time INT,
@minimum_run_duration INT,
@run_status INT,
@minimum_retries INT,
@oldest_first INT,
@server sysname,
@mode VARCHAR(7),
@order_by INT,
@distributed_job_history BIT
AS
-- Summary format: same WHERE clause as for full, just a different SELECT list
IF(@distributed_job_history = 1)
SELECT sj.job_id,
job_name = sj.name,
sjh.last_run_outcome as run_status,
sjh.last_run_date as run_date,
sjh.last_run_time as run_time,
sjh.last_run_duration as run_duration,
null as operator_emailed,
null as operator_netsentname,
null as operator_paged,
null as retries_attempted,
sts.server_name as server
FROM msdb.dbo.sysjobservers sjh
JOIN msdb.dbo.systargetservers sts ON (sts.server_id = sjh.server_id)
JOIN msdb.dbo.sysjobs_view sj ON(sj.job_id = sjh.job_id)
WHERE
(@job_id = sjh.job_id)
AND ((@start_run_date IS NULL) OR (sjh.last_run_date >= @start_run_date))
AND ((@end_run_date IS NULL) OR (sjh.last_run_date <= @end_run_date))
AND ((@start_run_time IS NULL) OR (sjh.last_run_time >= @start_run_time))
AND ((@minimum_run_duration IS NULL) OR (sjh.last_run_duration >= @minimum_run_duration))
AND ((@run_status IS NULL) OR (@run_status = sjh.last_run_outcome))
AND ((@server IS NULL) OR (sts.server_name = @server))
ELSE
SELECT sj.job_id,
job_name = sj.name,
sjh.run_status,
sjh.run_date,
sjh.run_time,
sjh.run_duration,
operator_emailed = substring(so1.name, 1, 20),
operator_netsent = substring(so2.name, 1, 20),
operator_paged = substring(so3.name, 1, 20),
sjh.retries_attempted,
sjh.server
FROM msdb.dbo.sysjobhistory sjh
LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjh.operator_id_emailed = so1.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjh.operator_id_netsent = so2.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjh.operator_id_paged = so3.id),
msdb.dbo.sysjobs_view sj
WHERE (sj.job_id = sjh.job_id)
AND ((@job_id IS NULL) OR (@job_id = sjh.job_id))
AND ((@step_id IS NULL) OR (@step_id = sjh.step_id))
AND ((@sql_message_id IS NULL) OR (@sql_message_id = sjh.sql_message_id))
AND ((@sql_severity IS NULL) OR (@sql_severity = sjh.sql_severity))
AND ((@start_run_date IS NULL) OR (sjh.run_date >= @start_run_date))
AND ((@end_run_date IS NULL) OR (sjh.run_date <= @end_run_date))
AND ((@start_run_time IS NULL) OR (sjh.run_time >= @start_run_time))
AND ((@end_run_time IS NULL) OR (sjh.run_time <= @end_run_time))
AND ((@minimum_run_duration IS NULL) OR (sjh.run_duration >= @minimum_run_duration))
AND ((@run_status IS NULL) OR (@run_status = sjh.run_status))
AND ((@minimum_retries IS NULL) OR (sjh.retries_attempted >= @minimum_retries))
AND ((@server IS NULL) OR (sjh.server = @server))
ORDER BY (sjh.instance_id * @order_by)
GO
/**************************************************************/
/* SP_HELP_JOBHISTORY */
/**************************************************************/
use [msdb]
PRINT ''
PRINT 'Creating procedure sp_help_jobhistory...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_jobhistory')
AND (type = 'P')))
DROP PROCEDURE sp_help_jobhistory
go
CREATE PROCEDURE [dbo].[sp_help_jobhistory]
@job_id UNIQUEIDENTIFIER = NULL,
@job_name sysname = NULL,
@step_id INT = NULL,
@sql_message_id INT = NULL,
@sql_severity INT = NULL,
@start_run_date INT = NULL, -- YYYYMMDD
@end_run_date INT = NULL, -- YYYYMMDD
@start_run_time INT = NULL, -- HHMMSS
@end_run_time INT = NULL, -- HHMMSS
@minimum_run_duration INT = NULL, -- HHMMSS
@run_status INT = NULL, -- SQLAGENT_EXEC_X code
@minimum_retries INT = NULL,
@oldest_first INT = 0, -- Or 1
@server sysname = NULL,
@mode VARCHAR(7) = 'SUMMARY' -- Or 'FULL' or 'SEM'
AS
BEGIN
DECLARE @retval INT
DECLARE @order_by INT -- Must be INT since it can be -1
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @server = LTRIM(RTRIM(@server))
SELECT @mode = LTRIM(RTRIM(@mode))
-- Turn [nullable] empty string parameters into NULLs
IF (@server = N'') SELECT @server = NULL
-- Check job id/name (if supplied)
IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
BEGIN
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Check @start_run_date
IF (@start_run_date IS NOT NULL)
BEGIN
EXECUTE @retval = sp_verify_job_date @start_run_date, '@start_run_date'
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Check @end_run_date
IF (@end_run_date IS NOT NULL)
BEGIN
EXECUTE @retval = sp_verify_job_date @end_run_date, '@end_run_date'
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Check @start_run_time
EXECUTE @retval = sp_verify_job_time @start_run_time, '@start_run_time'
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check @end_run_time
EXECUTE @retval = sp_verify_job_time @end_run_time, '@end_run_time'
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check @run_status
IF ((@run_status < 0) OR (@run_status > 5))
BEGIN
RAISERROR(14198, -1, -1, '@run_status', '0..5')
RETURN(1) -- Failure
END
-- Check mode
SELECT @mode = UPPER(@mode collate SQL_Latin1_General_CP1_CS_AS)
IF (@mode NOT IN ('SUMMARY', 'FULL', 'SEM'))
BEGIN
RAISERROR(14266, -1, -1, '@mode', 'SUMMARY, FULL, SEM')
RETURN(1) -- Failure
END
SELECT @order_by = -1
IF (@oldest_first = 1)
SELECT @order_by = 1
DECLARE @distributed_job_history BIT
SET @distributed_job_history = 0
IF (@job_id IS NOT NULL) AND ( EXISTS (SELECT *
FROM msdb.dbo.sysjobs sj,
msdb.dbo.sysjobservers sjs
WHERE (sj.job_id = sjs.job_id)
AND (sj.job_id = @job_id)
AND (sjs.server_id <> 0)))
SET @distributed_job_history = 1
-- Return history information filtered by the supplied parameters.
-- Having actual queries in subprocedures allows better query plans because query optimizer sniffs correct parameters
IF (@mode = 'FULL')
BEGIN
-- NOTE: SQLDMO relies on the 'FULL' format; ** DO NOT CHANGE IT **
EXECUTE sp_help_jobhistory_full
@job_id,
@job_name,
@step_id,
@sql_message_id,
@sql_severity,
@start_run_date,
@end_run_date,
@start_run_time,
@end_run_time,
@minimum_run_duration,
@run_status,
@minimum_retries,
@oldest_first,
@server,
@mode,
@order_by,
@distributed_job_history
END
ELSE
IF (@mode = 'SUMMARY')
BEGIN
-- Summary format: same WHERE clause as for full, just a different SELECT list
EXECUTE sp_help_jobhistory_summary
@job_id,
@job_name,
@step_id,
@sql_message_id,
@sql_severity,
@start_run_date,
@end_run_date,
@start_run_time,
@end_run_time,
@minimum_run_duration,
@run_status,
@minimum_retries,
@oldest_first,
@server,
@mode,
@order_by,
@distributed_job_history
END
ELSE
IF (@mode = 'SEM')
BEGIN
-- SQL Enterprise Manager format
EXECUTE sp_help_jobhistory_sem
@job_id,
@job_name,
@step_id,
@sql_message_id,
@sql_severity,
@start_run_date,
@end_run_date,
@start_run_time,
@end_run_time,
@minimum_run_duration,
@run_status,
@minimum_retries,
@oldest_first,
@server,
@mode,
@order_by,
@distributed_job_history
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_ADD_JOBSERVER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_jobserver...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_jobserver')
AND (type = 'P')))
DROP PROCEDURE sp_add_jobserver
go
CREATE PROCEDURE sp_add_jobserver
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@server_name sysname = NULL, -- if NULL will default to serverproperty('ServerName')
@automatic_post BIT = 1 -- Flag for SEM use only
AS
BEGIN
DECLARE @retval INT
DECLARE @server_id INT
DECLARE @job_type VARCHAR(12)
DECLARE @current_job_category_type VARCHAR(12)
DECLARE @msx_operator_id INT
DECLARE @local_server_name sysname
DECLARE @is_sysadmin INT
DECLARE @job_owner sysname
DECLARE @owner_sid VARBINARY(85)
DECLARE @owner_name sysname
SET NOCOUNT ON
IF (@server_name IS NULL) OR (UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = N'(LOCAL)')
SELECT @server_name = CONVERT(sysname, SERVERPROPERTY('ServerName'))
-- Remove any leading/trailing spaces from parameters
SELECT @server_name = UPPER(LTRIM(RTRIM(@server_name)))
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- First, check if the server is the local server
SELECT @local_server_name = CONVERT(NVARCHAR,SERVERPROPERTY ('SERVERNAME'))
IF (@server_name = UPPER(@local_server_name))
SELECT @server_name = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))
-- For a multi-server job...
IF (@server_name <> UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))
BEGIN
-- 1) Only sysadmin can add a multi-server job
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0)
BEGIN
RAISERROR(14398, -1, -1);
RETURN(1) -- Failure
END
-- 2) Job must be owned by sysadmin
SELECT @owner_sid = owner_sid, @owner_name = dbo.SQLAGENT_SUSER_SNAME(owner_sid)
FROM msdb.dbo.sysjobs
WHERE (job_id = @job_id)
IF @owner_sid = 0xFFFFFFFF
BEGIN
SELECT @is_sysadmin = 1
END
ELSE
BEGIN
SELECT @is_sysadmin = 0
EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @owner_name, @is_sysadmin_member = @is_sysadmin OUTPUT
END
IF (@is_sysadmin = 0)
BEGIN
RAISERROR(14544, -1, -1, @owner_name, N'sysadmin')
RETURN(1) -- Failure
END
-- 3) Check if any of the TSQL steps have a non-null database_user_name
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND (subsystem = N'TSQL')
AND (database_user_name IS NOT NULL)))
BEGIN
RAISERROR(14542, -1, -1, N'database_user_name')
RETURN(1) -- Failure
END
SELECT @server_id = server_id
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = @server_name)
IF (@server_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@server_name', @server_name)
RETURN(1) -- Failure
END
END
ELSE
SELECT @server_id = 0
-- Check that this job has not already been targeted at this server
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = @server_id)))
BEGIN
RAISERROR(14269, -1, -1, @job_name, @server_name)
RETURN(1) -- Failure
END
-- Prevent the job from being targeted at both the local AND remote servers
SELECT @job_type = 'UNKNOWN'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)))
SELECT @job_type = 'LOCAL'
ELSE
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id <> 0)))
SELECT @job_type = 'MULTI-SERVER'
IF ((@server_id = 0) AND (@job_type = 'MULTI-SERVER'))
BEGIN
RAISERROR(14290, -1, -1)
RETURN(1) -- Failure
END
IF ((@server_id <> 0) AND (@job_type = 'LOCAL'))
BEGIN
RAISERROR(14291, -1, -1)
RETURN(1) -- Failure
END
-- For a multi-server job, check that any notifications are to the MSXOperator
IF (@job_type = 'MULTI-SERVER')
BEGIN
SELECT @msx_operator_id = id
FROM msdb.dbo.sysoperators
WHERE (name = N'MSXOperator')
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobs
WHERE (job_id = @job_id)
AND (((notify_email_operator_id <> 0) AND (notify_email_operator_id <> @msx_operator_id)) OR
((notify_page_operator_id <> 0) AND (notify_page_operator_id <> @msx_operator_id)) OR
((notify_netsend_operator_id <> 0) AND (notify_netsend_operator_id <> @msx_operator_id)))))
BEGIN
RAISERROR(14221, -1, -1, 'MSXOperator')
RETURN(1) -- Failure
END
END
-- Insert the sysjobservers row
INSERT INTO msdb.dbo.sysjobservers
(job_id,
server_id,
last_run_outcome,
last_outcome_message,
last_run_date,
last_run_time,
last_run_duration)
VALUES (@job_id,
@server_id,
5, -- ie. SQLAGENT_EXEC_UNKNOWN (can't use 0 since this is SQLAGENT_EXEC_FAIL)
NULL,
0,
0,
0)
-- Re-categorize the job (if necessary)
SELECT @current_job_category_type = CASE category_type
WHEN 1 THEN 'LOCAL'
WHEN 2 THEN 'MULTI-SERVER'
END
FROM msdb.dbo.sysjobs_view sjv,
msdb.dbo.syscategories sc
WHERE (sjv.category_id = sc.category_id)
AND (sjv.job_id = @job_id)
IF (@server_id = 0) AND (@current_job_category_type = 'MULTI-SERVER')
BEGIN
UPDATE msdb.dbo.sysjobs
SET category_id = 0 -- [Uncategorized (Local)]
WHERE (job_id = @job_id)
END
IF (@server_id <> 0) AND (@current_job_category_type = 'LOCAL')
BEGIN
UPDATE msdb.dbo.sysjobs
SET category_id = 2 -- [Uncategorized (Multi-Server)]
WHERE (job_id = @job_id)
END
-- Instruct the new server to pick up the job
IF (@automatic_post = 1)
EXECUTE @retval = sp_post_msx_operation 'INSERT', 'JOB', @job_id, @server_name
-- If the job is local, make sure that SQLServerAgent caches it
IF (@server_id = 0)
BEGIN
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',
@job_id = @job_id,
@action_type = N'I'
END
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_DELETE_JOBSERVER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_jobserver...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_jobserver')
AND (type = 'P')))
DROP PROCEDURE sp_delete_jobserver
go
CREATE PROCEDURE sp_delete_jobserver
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@server_name sysname
AS
BEGIN
DECLARE @retval INT
DECLARE @server_id INT
DECLARE @local_machine_name sysname
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @server_name = LTRIM(RTRIM(@server_name))
IF (UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = '(LOCAL)')
SELECT @server_name = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- First, check if the server is the local server
EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
IF (@local_machine_name IS NOT NULL) AND (UPPER(@server_name) = UPPER(@local_machine_name))
SELECT @server_name = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))
-- Check server name
IF (UPPER(@server_name) <> UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))
BEGIN
SELECT @server_id = server_id
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = @server_name)
IF (@server_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@server_name', @server_name)
RETURN(1) -- Failure
END
END
ELSE
SELECT @server_id = 0
-- Check that the job is indeed targeted at the server
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = @server_id)))
BEGIN
RAISERROR(14270, -1, -1, @job_name, @server_name)
RETURN(1) -- Failure
END
-- Instruct the deleted server to purge the job
-- NOTE: We must do this BEFORE we delete the sysjobservers row
EXECUTE @retval = sp_post_msx_operation 'DELETE', 'JOB', @job_id, @server_name
-- Delete the sysjobservers row
DELETE FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = @server_id)
-- We used to change the category_id to 0 when removing the last job server
-- from a job. We no longer do this.
-- IF (NOT EXISTS (SELECT *
-- FROM msdb.dbo.sysjobservers
-- WHERE (job_id = @job_id)))
-- BEGIN
-- UPDATE msdb.dbo.sysjobs
-- SET category_id = 0 -- [Uncategorized (Local)]
-- WHERE (job_id = @job_id)
-- END
-- If the job is local, make sure that SQLServerAgent removes it from cache
IF (@server_id = 0)
BEGIN
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',
@job_id = @job_id,
@action_type = N'D'
END
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_HELP_JOBSERVER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_jobserver...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_jobserver')
AND (type = 'P')))
DROP PROCEDURE sp_help_jobserver
go
CREATE PROCEDURE sp_help_jobserver
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@show_last_run_details TINYINT = 0 -- Controls if last-run execution information is part of the result set (1 = yes, 0 = no)
AS
BEGIN
DECLARE @retval INT
SET NOCOUNT ON
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- The show-last-run-details flag must be either 1 or 0
IF (@show_last_run_details <> 0)
SELECT @show_last_run_details = 1
IF (@show_last_run_details = 1)
BEGIN
-- List the servers that @job_name has been targeted at (INCLUDING last-run details)
SELECT stsv.server_id,
stsv.server_name,
stsv.enlist_date,
stsv.last_poll_date,
sjs.last_run_date,
sjs.last_run_time,
sjs.last_run_duration,
sjs.last_run_outcome, -- Same as JOB_OUTCOME_CODE (SQLAGENT_EXEC_x)
sjs.last_outcome_message
FROM msdb.dbo.sysjobservers sjs LEFT OUTER JOIN
msdb.dbo.systargetservers_view stsv ON (sjs.server_id = stsv.server_id)
WHERE (sjs.job_id = @job_id)
END
ELSE
BEGIN
-- List the servers that @job_name has been targeted at (EXCLUDING last-run details)
SELECT stsv.server_id,
stsv.server_name,
stsv.enlist_date,
stsv.last_poll_date
FROM msdb.dbo.sysjobservers sjs LEFT OUTER JOIN
msdb.dbo.systargetservers_view stsv ON (sjs.server_id = stsv.server_id)
WHERE (sjs.job_id = @job_id)
END
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_HELP_DOWNLOADLIST */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_downloadlist...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_downloadlist')
AND (type = 'P')))
DROP PROCEDURE sp_help_downloadlist
go
CREATE PROCEDURE sp_help_downloadlist
@job_id UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name
@job_name sysname = NULL, -- If provided must NOT also provide job_id
@operation VARCHAR(64) = NULL,
@object_type VARCHAR(64) = NULL, -- Only 'JOB' or 'SERVER' are valid in 7.0
@object_name sysname = NULL,
@target_server sysname = NULL,
@has_error TINYINT = NULL, -- NULL or 1
@status TINYINT = NULL,
@date_posted DATETIME = NULL -- Include all entries made on OR AFTER this date
AS
BEGIN
DECLARE @retval INT
DECLARE @operation_code INT
DECLARE @object_type_id TINYINT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @operation = LTRIM(RTRIM(@operation))
SELECT @object_type = LTRIM(RTRIM(@object_type))
SELECT @object_name = LTRIM(RTRIM(@object_name))
SELECT @target_server = UPPER(LTRIM(RTRIM(@target_server)))
-- Turn [nullable] empty string parameters into NULLs
IF (@operation = '') SELECT @operation = NULL
IF (@object_type = '') SELECT @object_type = NULL
IF (@object_name = N'') SELECT @object_name = NULL
IF (@target_server = N'') SELECT @target_server = NULL
IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
BEGIN
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Check operation
IF (@operation IS NOT NULL)
BEGIN
SELECT @operation = UPPER(@operation collate SQL_Latin1_General_CP1_CS_AS)
SELECT @operation_code = CASE @operation
WHEN 'INSERT' THEN 1
WHEN 'UPDATE' THEN 2
WHEN 'DELETE' THEN 3
WHEN 'START' THEN 4
WHEN 'STOP' THEN 5
WHEN 'RE-ENLIST' THEN 6
WHEN 'DEFECT' THEN 7
WHEN 'SYNC-TIME' THEN 8
WHEN 'SET-POLL' THEN 9
ELSE 0
END
IF (@operation_code = 0)
BEGIN
RAISERROR(14266, -1, -1, '@operation_code', 'INSERT, UPDATE, DELETE, START, STOP, RE-ENLIST, DEFECT, SYNC-TIME, SET-POLL')
RETURN(1) -- Failure
END
END
-- Check object type (in 7.0 only 'JOB' and 'SERVER' are valid)
IF (@object_type IS NOT NULL)
BEGIN
SELECT @object_type = UPPER(@object_type collate SQL_Latin1_General_CP1_CS_AS)
IF ((@object_type <> 'JOB') AND (@object_type <> 'SERVER'))
BEGIN
RAISERROR(14266, -1, -1, '@object_type', 'JOB, SERVER')
RETURN(1) -- Failure
END
ELSE
SELECT @object_type_id = CASE @object_type
WHEN 'JOB' THEN 1
WHEN 'SERVER' THEN 2
ELSE 0
END
END
-- If object-type is supplied then object-name must also be supplied
IF ((@object_type IS NOT NULL) AND (@object_name IS NULL)) OR
((@object_type IS NULL) AND (@object_name IS NOT NULL))
BEGIN
RAISERROR(14272, -1, -1)
RETURN(1) -- Failure
END
-- Check target server
IF (@target_server IS NOT NULL) AND NOT EXISTS (SELECT *
FROM msdb.dbo.systargetservers
WHERE UPPER(server_name) = @target_server)
BEGIN
RAISERROR(14262, -1, -1, '@target_server', @target_server)
RETURN(1) -- Failure
END
-- Check has-error
IF (@has_error IS NOT NULL) AND (@has_error <> 1)
BEGIN
RAISERROR(14266, -1, -1, '@has_error', '1, NULL')
RETURN(1) -- Failure
END
-- Check status
IF (@status IS NOT NULL) AND (@status <> 0) AND (@status <> 1)
BEGIN
RAISERROR(14266, -1, -1, '@status', '0, 1')
RETURN(1) -- Failure
END
-- Return the result set
SELECT sdl.instance_id,
sdl.source_server,
'operation_code' = CASE sdl.operation_code
WHEN 1 THEN '1 (INSERT)'
WHEN 2 THEN '2 (UPDATE)'
WHEN 3 THEN '3 (DELETE)'
WHEN 4 THEN '4 (START)'
WHEN 5 THEN '5 (STOP)'
WHEN 6 THEN '6 (RE-ENLIST)'
WHEN 7 THEN '7 (DEFECT)'
WHEN 8 THEN '8 (SYNC-TIME)'
WHEN 9 THEN '9 (SET-POLL)'
ELSE CONVERT(VARCHAR, sdl.operation_code) + ' ' + FORMATMESSAGE(14205)
END,
'object_name' = ISNULL(sjv.name, CASE
WHEN (sdl.operation_code >= 1) AND (sdl.operation_code <= 5) AND (sdl.object_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) THEN FORMATMESSAGE(14212) -- '(all jobs)'
WHEN (sdl.operation_code = 3) AND (sdl.object_id <> CONVERT(UNIQUEIDENTIFIER, 0x00)) THEN sdl.deleted_object_name -- Special case handling for a deleted job
WHEN (sdl.operation_code >= 1) AND (sdl.operation_code <= 5) AND (sdl.object_id <> CONVERT(UNIQUEIDENTIFIER, 0x00)) THEN FORMATMESSAGE(14580) -- 'job' (safety belt: should never appear)
WHEN (sdl.operation_code >= 6) AND (sdl.operation_code <= 9) THEN sdl.target_server
ELSE FORMATMESSAGE(14205)
END),
'object_id' = ISNULL(sjv.job_id, CASE sdl.object_id
WHEN CONVERT(UNIQUEIDENTIFIER, 0x00) THEN CONVERT(UNIQUEIDENTIFIER, 0x00)
ELSE sdl.object_id
END),
sdl.target_server,
sdl.error_message,
sdl.date_posted,
sdl.date_downloaded,
sdl.status
FROM msdb.dbo.sysdownloadlist sdl LEFT OUTER JOIN
msdb.dbo.sysjobs_view sjv ON (sdl.object_id = sjv.job_id)
WHERE ((@operation_code IS NULL) OR (operation_code = @operation_code))
AND ((@object_type_id IS NULL) OR (object_type = @object_type_id))
AND ((@job_id IS NULL) OR (object_id = @job_id))
AND ((@target_server IS NULL) OR (target_server = @target_server))
AND ((@has_error IS NULL) OR (DATALENGTH(error_message) >= 1 * @has_error))
AND ((@status IS NULL) OR (status = @status))
AND ((@date_posted IS NULL) OR (date_posted >= @date_posted))
ORDER BY sdl.instance_id
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_ENUM_SQLAGENT_SUBSYSTEMS_INTERNAL */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_enum_sqlagent_subsystems_internal...'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_enum_sqlagent_subsystems_internal')
AND (type = 'P')))
DROP PROCEDURE sp_enum_sqlagent_subsystems_internal
go
CREATE PROCEDURE sp_enum_sqlagent_subsystems_internal
@syssubsytems_refresh_needed BIT = 0
AS
BEGIN
DECLARE @retval INT
SET NOCOUNT ON
-- this call will populate subsystems table if necessary
EXEC @retval = msdb.dbo.sp_verify_subsystems @syssubsytems_refresh_needed
IF @retval <> 0
RETURN(@retval)
-- Check if replication is installed
DECLARE @replication_installed INT
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\Replication',
N'IsInstalled',
@replication_installed OUTPUT,
N'no_output'
SELECT @replication_installed = ISNULL(@replication_installed, 0)
IF @replication_installed = 0
SELECT subsystem,
description = FORMATMESSAGE(description_id),
subsystem_dll,
agent_exe,
start_entry_point,
event_entry_point,
stop_entry_point,
max_worker_threads,
subsystem_id
FROM syssubsystems
WHERE (subsystem NOT IN (N'Distribution', N'LogReader', N'Merge', N'Snapshot', N'QueueReader'))
ORDER by subsystem
ELSE
SELECT subsystem,
description = FORMATMESSAGE(description_id),
subsystem_dll,
agent_exe,
start_entry_point,
event_entry_point,
stop_entry_point,
max_worker_threads,
subsystem_id
FROM syssubsystems
ORDER by subsystem_id
RETURN(0)
END
go
/**************************************************************/
/* SP_ENUM_SQLAGENT_SUBSYSTEMS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_enum_sqlagent_subsystems...'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_enum_sqlagent_subsystems')
AND (type = 'P')))
DROP PROCEDURE sp_enum_sqlagent_subsystems
go
CREATE PROCEDURE sp_enum_sqlagent_subsystems
AS
BEGIN
DECLARE @retval INT
EXEC @retval = msdb.dbo.sp_enum_sqlagent_subsystems_internal
RETURN(@retval)
END
go
/**************************************************************/
/* SP_VERIFY_SUBSYSTEM */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_subsystem...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_subsystem')
AND (type = 'P')))
DROP PROCEDURE sp_verify_subsystem
go
CREATE PROCEDURE sp_verify_subsystem
@subsystem NVARCHAR(40)
AS
BEGIN
DECLARE @retval INT
SET NOCOUNT ON
-- this call will populate subsystems table if necessary
EXEC @retval = msdb.dbo.sp_verify_subsystems
IF @retval <> 0
RETURN(@retval)
-- Remove any leading/trailing spaces from parameters
SELECT @subsystem = LTRIM(RTRIM(@subsystem))
-- Make sure Dts is translated into new subsystem's name SSIS
IF (@subsystem IS NOT NULL AND UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'DTS')
BEGIN
SET @subsystem = N'SSIS'
END
IF EXISTS (SELECT * FROM syssubsystems
WHERE UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) =
UPPER(subsystem collate SQL_Latin1_General_CP1_CS_AS))
RETURN(0) -- Success
ELSE
BEGIN
RAISERROR(14234, -1, -1, '@subsystem', 'sp_enum_sqlagent_subsystems')
RETURN(1) -- Failure
END
END
go
/**************************************************************/
/* SP_VERIFY_SCHEDULE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_schedule...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_schedule')
AND (type = 'P')))
DROP PROCEDURE sp_verify_schedule
go
CREATE PROCEDURE sp_verify_schedule
@schedule_id INT,
@name sysname,
@enabled TINYINT,
@freq_type INT,
@freq_interval INT OUTPUT, -- Output because we may set it to 0 if Frequency Type is one-time or auto-start
@freq_subday_type INT OUTPUT, -- As above
@freq_subday_interval INT OUTPUT, -- As above
@freq_relative_interval INT OUTPUT, -- As above
@freq_recurrence_factor INT OUTPUT, -- As above
@active_start_date INT OUTPUT,
@active_start_time INT OUTPUT,
@active_end_date INT OUTPUT,
@active_end_time INT OUTPUT,
@owner_sid VARBINARY(85) --Must be a valid sid. Will fail if this is NULL
AS
BEGIN
DECLARE @return_code INT
DECLARE @res_valid_range NVARCHAR(100)
DECLARE @reason NVARCHAR(200)
DECLARE @isAdmin INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
-- Make sure that NULL input/output parameters - if NULL - are initialized to 0
SELECT @freq_interval = ISNULL(@freq_interval, 0)
SELECT @freq_subday_type = ISNULL(@freq_subday_type, 0)
SELECT @freq_subday_interval = ISNULL(@freq_subday_interval, 0)
SELECT @freq_relative_interval = ISNULL(@freq_relative_interval, 0)
SELECT @freq_recurrence_factor = ISNULL(@freq_recurrence_factor, 0)
SELECT @active_start_date = ISNULL(@active_start_date, 0)
SELECT @active_start_time = ISNULL(@active_start_time, 0)
SELECT @active_end_date = ISNULL(@active_end_date, 0)
SELECT @active_end_time = ISNULL(@active_end_time, 0)
-- Check owner
IF(ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
SELECT @isAdmin = 1
ELSE
SELECT @isAdmin = 0
-- If a non-sa is [illegally] trying to create a schedule for another user then raise an error
IF ((@isAdmin <> 1) AND
(ISNULL(IS_MEMBER('SQLAgentOperatorRole'),0) <> 1 AND @schedule_id IS NULL) AND
(@owner_sid <> SUSER_SID()))
BEGIN
RAISERROR(14366, -1, -1)
RETURN(1) -- Failure
END
-- Now just check that the login id is valid (ie. it exists and isn't an NT group)
IF (@owner_sid <> 0x010100000000000512000000) AND -- NT AUTHORITY\SYSTEM sid
(@owner_sid <> 0x010100000000000514000000) -- NT AUTHORITY\NETWORK SERVICE sid
BEGIN
IF (@owner_sid IS NULL) OR (EXISTS (SELECT *
FROM master.dbo.syslogins
WHERE (sid = @owner_sid)
AND (isntgroup <> 0)))
BEGIN
-- NOTE: In the following message we quote @owner_login_name instead of @owner_sid
-- since this is the parameter the user passed to the calling SP (ie. either
-- sp_add_schedule, sp_add_job and sp_update_job)
SELECT @res_valid_range = FORMATMESSAGE(14203)
RAISERROR(14234, -1, -1, '@owner_login_name', @res_valid_range)
RETURN(1) -- Failure
END
END
-- Verify name (we disallow schedules called 'ALL' since this has special meaning in sp_delete_jobschedules)
IF (UPPER(@name collate SQL_Latin1_General_CP1_CS_AS) = N'ALL')
BEGIN
RAISERROR(14200, -1, -1, '@name')
RETURN(1) -- Failure
END
-- Verify enabled state
IF (@enabled <> 0) AND (@enabled <> 1)
BEGIN
RAISERROR(14266, -1, -1, '@enabled', '0, 1')
RETURN(1) -- Failure
END
-- Verify frequency type
IF (@freq_type = 0x2) -- OnDemand is no longer supported
BEGIN
RAISERROR(14295, -1, -1)
RETURN(1) -- Failure
END
IF (@freq_type NOT IN (0x1, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80))
BEGIN
RAISERROR(14266, -1, -1, '@freq_type', '1, 4, 8, 16, 32, 64, 128')
RETURN(1) -- Failure
END
-- Verify frequency sub-day type
IF (@freq_subday_type <> 0) AND (@freq_subday_type NOT IN (0x1, 0x2, 0x4, 0x8))
BEGIN
RAISERROR(14266, -1, -1, '@freq_subday_type', '0x1, 0x2, 0x4, 0x8')
RETURN(1) -- Failure
END
-- Default active start/end date/times (if not supplied, or supplied as NULLs or 0)
IF (@active_start_date = 0)
SELECT @active_start_date = DATEPART(yy, GETDATE()) * 10000 +
DATEPART(mm, GETDATE()) * 100 +
DATEPART(dd, GETDATE()) -- This is an ISO format: "yyyymmdd"
IF (@active_end_date = 0)
SELECT @active_end_date = 99991231 -- December 31st 9999
IF (@active_start_time = 0)
SELECT @active_start_time = 000000 -- 12:00:00 am
IF (@active_end_time = 0)
SELECT @active_end_time = 235959 -- 11:59:59 pm
-- Verify active start/end dates
IF (@active_end_date = 0)
SELECT @active_end_date = 99991231
EXECUTE @return_code = sp_verify_job_date @active_end_date, '@active_end_date'
IF (@return_code <> 0)
RETURN(1) -- Failure
EXECUTE @return_code = sp_verify_job_date @active_start_date, '@active_start_date'
IF (@return_code <> 0)
RETURN(1) -- Failure
IF (@active_end_date < @active_start_date)
BEGIN
RAISERROR(14288, -1, -1, '@active_end_date', '@active_start_date')
RETURN(1) -- Failure
END
EXECUTE @return_code = sp_verify_job_time @active_end_time, '@active_end_time'
IF (@return_code <> 0)
RETURN(1) -- Failure
EXECUTE @return_code = sp_verify_job_time @active_start_time, '@active_start_time'
IF (@return_code <> 0)
RETURN(1) -- Failure
-- NOTE: It's valid for active_end_time to be less than active_start_time since in this
-- case we assume that the user wants the active time zone to span midnight.
-- But it's not valid for active_start_date and active_end_date to be the same for recurring sec/hour/minute schedules
IF (@active_start_time = @active_end_time and (@freq_subday_type in (0x2, 0x4, 0x8)))
BEGIN
SELECT @res_valid_range = FORMATMESSAGE(14202)
RAISERROR(14266, -1, -1, '@active_end_time', @res_valid_range)
RETURN(1) -- Failure
END
-- NOTE: The rest of this procedure is a SQL implementation of VerifySchedule in job.c
IF ((@freq_type = 0x1) OR -- FREQTYPE_ONETIME
(@freq_type = 0x40) OR -- FREQTYPE_AUTOSTART
(@freq_type = 0x80)) -- FREQTYPE_ONIDLE
BEGIN
-- Set standard defaults for non-required parameters
SELECT @freq_interval = 0
SELECT @freq_subday_type = 0
SELECT @freq_subday_interval = 0
SELECT @freq_relative_interval = 0
SELECT @freq_recurrence_factor = 0
-- Check that a one-time schedule isn't already in the past
-- Bug 442883: let the creation of the one-time schedule succeed but leave a disabled schedule
/*
IF (@freq_type = 0x1) -- FREQTYPE_ONETIME
BEGIN
DECLARE @current_date INT
DECLARE @current_time INT
-- This is an ISO format: "yyyymmdd"
SELECT @current_date = CONVERT(INT, CONVERT(VARCHAR, GETDATE(), 112))
SELECT @current_time = (DATEPART(hh, GETDATE()) * 10000) + (DATEPART(mi, GETDATE()) * 100) + DATEPART(ss, GETDATE())
IF (@active_start_date < @current_date) OR ((@active_start_date = @current_date) AND (@active_start_time <= @current_time))
BEGIN
SELECT @res_valid_range = '> ' + CONVERT(VARCHAR, @current_date) + ' / ' + CONVERT(VARCHAR, @current_time)
SELECT @reason = '@active_start_date = ' + CONVERT(VARCHAR, @active_start_date) + ' / @active_start_time = ' + CONVERT(VARCHAR, @active_start_time)
RAISERROR(14266, -1, -1, @reason, @res_valid_range)
RETURN(1) -- Failure
END
END
*/
GOTO ExitProc
END
-- Safety net: If the sub-day-type is 0 (and we know that the schedule is not a one-time or
-- auto-start) then set it to 1 (FREQSUBTYPE_ONCE). If the user wanted something
-- other than ONCE then they should have explicitly set @freq_subday_type.
IF (@freq_subday_type = 0)
SELECT @freq_subday_type = 0x1 -- FREQSUBTYPE_ONCE
IF ((@freq_subday_type <> 0x1) AND -- FREQSUBTYPE_ONCE (see qsched.h)
(@freq_subday_type <> 0x2) AND -- FREQSUBTYPE_SECOND (see qsched.h)
(@freq_subday_type <> 0x4) AND -- FREQSUBTYPE_MINUTE (see qsched.h)
(@freq_subday_type <> 0x8)) -- FREQSUBTYPE_HOUR (see qsched.h)
BEGIN
SELECT @reason = FORMATMESSAGE(14266, '@freq_subday_type', '0x1, 0x2, 0x4, 0x8')
RAISERROR(14278, -1, -1, @reason)
RETURN(1) -- Failure
END
IF ((@freq_subday_type <> 0x1) AND (@freq_subday_interval < 1)) -- FREQSUBTYPE_ONCE and less than 1 interval
OR
((@freq_subday_type = 0x2) AND (@freq_subday_interval < 10)) -- FREQSUBTYPE_SECOND and less than 10 seconds (see MIN_SCHEDULE_GRANULARITY in SqlAgent source code)
BEGIN
SELECT @reason = FORMATMESSAGE(14200, '@freq_subday_interval')
RAISERROR(14278, -1, -1, @reason)
RETURN(1) -- Failure
END
IF (@freq_type = 0x4) -- FREQTYPE_DAILY
BEGIN
SELECT @freq_recurrence_factor = 0
IF (@freq_interval < 1)
BEGIN
SELECT @reason = FORMATMESSAGE(14572)
RAISERROR(14278, -1, -1, @reason)
RETURN(1) -- Failure
END
END
IF (@freq_type = 0x8) -- FREQTYPE_WEEKLY
BEGIN
IF (@freq_interval < 1) OR
(@freq_interval > 127) -- (2^7)-1 [freq_interval is a bitmap (Sun=1..Sat=64)]
BEGIN
SELECT @reason = FORMATMESSAGE(14573)
RAISERROR(14278, -1, -1, @reason)
RETURN(1) -- Failure
END
END
IF (@freq_type = 0x10) -- FREQTYPE_MONTHLY
BEGIN
IF (@freq_interval < 1) OR
(@freq_interval > 31)
BEGIN
SELECT @reason = FORMATMESSAGE(14574)
RAISERROR(14278, -1, -1, @reason)
RETURN(1) -- Failure
END
END
IF (@freq_type = 0x20) -- FREQTYPE_MONTHLYRELATIVE
BEGIN
IF (@freq_relative_interval <> 0x01) AND -- RELINT_1ST
(@freq_relative_interval <> 0x02) AND -- RELINT_2ND
(@freq_relative_interval <> 0x04) AND -- RELINT_3RD
(@freq_relative_interval <> 0x08) AND -- RELINT_4TH
(@freq_relative_interval <> 0x10) -- RELINT_LAST
BEGIN
SELECT @reason = FORMATMESSAGE(14575)
RAISERROR(14278, -1, -1, @reason)
RETURN(1) -- Failure
END
END
IF (@freq_type = 0x20) -- FREQTYPE_MONTHLYRELATIVE
BEGIN
IF (@freq_interval <> 01) AND -- RELATIVE_SUN
(@freq_interval <> 02) AND -- RELATIVE_MON
(@freq_interval <> 03) AND -- RELATIVE_TUE
(@freq_interval <> 04) AND -- RELATIVE_WED
(@freq_interval <> 05) AND -- RELATIVE_THU
(@freq_interval <> 06) AND -- RELATIVE_FRI
(@freq_interval <> 07) AND -- RELATIVE_SAT
(@freq_interval <> 08) AND -- RELATIVE_DAY
(@freq_interval <> 09) AND -- RELATIVE_WEEKDAY
(@freq_interval <> 10) -- RELATIVE_WEEKENDDAY
BEGIN
SELECT @reason = FORMATMESSAGE(14576)
RAISERROR(14278, -1, -1, @reason)
RETURN(1) -- Failure
END
END
IF ((@freq_type = 0x08) OR -- FREQTYPE_WEEKLY
(@freq_type = 0x10) OR -- FREQTYPE_MONTHLY
(@freq_type = 0x20)) AND -- FREQTYPE_MONTHLYRELATIVE
(@freq_recurrence_factor < 1)
BEGIN
SELECT @reason = FORMATMESSAGE(14577)
RAISERROR(14278, -1, -1, @reason)
RETURN(1) -- Failure
END
ExitProc:
-- If we made it this far the schedule is good
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_ADD_SCHEDULE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_schedule...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_schedule')
AND (type = 'P')))
DROP PROCEDURE sp_add_schedule
go
CREATE PROCEDURE sp_add_schedule
(
@schedule_name sysname,
@enabled TINYINT = 1, -- Name does not have to be unique
@freq_type INT = 0,
@freq_interval INT = 0,
@freq_subday_type INT = 0,
@freq_subday_interval INT = 0,
@freq_relative_interval INT = 0,
@freq_recurrence_factor INT = 0,
@active_start_date INT = NULL, -- sp_verify_schedule assigns a default
@active_end_date INT = 99991231, -- December 31st 9999
@active_start_time INT = 000000, -- 12:00:00 am
@active_end_time INT = 235959, -- 11:59:59 pm
@owner_login_name sysname = NULL,
@schedule_uid UNIQUEIDENTIFIER= NULL OUTPUT, -- Used by a TSX machine when inserting a schedule
@schedule_id INT = NULL OUTPUT,
@originating_server sysname = NULL
)
AS
BEGIN
DECLARE @retval INT
DECLARE @owner_sid VARBINARY(85)
DECLARE @orig_server_id INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @schedule_name = LTRIM(RTRIM(@schedule_name)),
@owner_login_name = LTRIM(RTRIM(@owner_login_name)),
@originating_server = UPPER(LTRIM(RTRIM(@originating_server))),
@schedule_id = 0
-- If the owner isn't supplied make if the current user
IF(@owner_login_name IS NULL OR @owner_login_name = '')
BEGIN
--Get the current users sid
SELECT @owner_sid = SUSER_SID()
END
ELSE
BEGIN
-- Get the sid for @owner_login_name SID
--force case insensitive comparation for NT users
SELECT @owner_sid = dbo.SQLAGENT_SUSER_SID(@owner_login_name)
-- Cannot proceed if @owner_login_name doesn't exist
IF(@owner_sid IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@owner_login_name', @owner_login_name)
RETURN(1) -- Failure
END
END
-- Check schedule (frequency and owner) parameters
EXECUTE @retval = sp_verify_schedule NULL, -- schedule_id does not exist for the new schedule
@name = @schedule_name,
@enabled = @enabled,
@freq_type = @freq_type,
@freq_interval = @freq_interval OUTPUT,
@freq_subday_type = @freq_subday_type OUTPUT,
@freq_subday_interval = @freq_subday_interval OUTPUT,
@freq_relative_interval = @freq_relative_interval OUTPUT,
@freq_recurrence_factor = @freq_recurrence_factor OUTPUT,
@active_start_date = @active_start_date OUTPUT,
@active_start_time = @active_start_time OUTPUT,
@active_end_date = @active_end_date OUTPUT,
@active_end_time = @active_end_time OUTPUT,
@owner_sid = @owner_sid
IF (@retval <> 0)
RETURN(1) -- Failure
-- ignore @originating_server unless SQLAgent is calling
if((@originating_server IS NULL) OR (@originating_server = N'') OR (PROGRAM_NAME() NOT LIKE N'SQLAgent%'))
BEGIN
--Get the local originating_server_id
SELECT @orig_server_id = originating_server_id
FROM msdb.dbo.sysoriginatingservers_view
WHERE master_server = 0
END
ELSE
BEGIN
--Get the MSX originating_server_id. If @originating_server isn't the msx server error out
SELECT @orig_server_id = originating_server_id
FROM msdb.dbo.sysoriginatingservers_view
WHERE (originating_server = @originating_server)
IF (@orig_server_id IS NULL)
BEGIN
RAISERROR(14370, -1, -1)
RETURN(1) -- Failure
END
END
IF (@schedule_uid IS NULL)
BEGIN
-- Assign the GUID
SELECT @schedule_uid = NEWID()
END
ELSE IF (@schedule_uid <> CONVERT(UNIQUEIDENTIFIER, 0x00))
BEGIN
--Try and find the schedule if a @schedule_uid is provided.
--A TSX server uses the @schedule_uid to identify a schedule downloaded from the MSX
SELECT @schedule_id = schedule_id
FROM msdb.dbo.sysschedules
WHERE schedule_uid = @schedule_uid
IF((@schedule_id IS NOT NULL) AND (@schedule_id <> 0))
BEGIN
--If found update the fields
UPDATE msdb.dbo.sysschedules
SET name = ISNULL(@schedule_name, name),
enabled = ISNULL(@enabled, enabled),
freq_type = ISNULL(@freq_type, freq_type),
freq_interval = ISNULL(@freq_interval, freq_interval),
freq_subday_type = ISNULL(@freq_subday_type, freq_subday_type),
freq_subday_interval = ISNULL(@freq_subday_interval, freq_subday_interval),
freq_relative_interval = ISNULL(@freq_relative_interval, freq_relative_interval),
freq_recurrence_factor = ISNULL(@freq_recurrence_factor, freq_recurrence_factor),
active_start_date = ISNULL(@active_start_date, active_start_date),
active_end_date = ISNULL(@active_end_date, active_end_date),
active_start_time = ISNULL(@active_start_time, active_start_time),
active_end_time = ISNULL(@active_end_time, active_end_time)
WHERE schedule_uid = @schedule_uid
RETURN(@@ERROR)
END
END
--MSX not found so add a record to sysschedules
INSERT INTO msdb.dbo.sysschedules
(schedule_uid,
originating_server_id,
name,
owner_sid,
enabled,
freq_type,
freq_interval,
freq_subday_type,
freq_subday_interval,
freq_relative_interval,
freq_recurrence_factor,
active_start_date,
active_end_date,
active_start_time,
active_end_time)
select @schedule_uid,
@orig_server_id,
@schedule_name,
@owner_sid,
@enabled,
@freq_type,
@freq_interval,
@freq_subday_type,
@freq_subday_interval,
@freq_relative_interval,
@freq_recurrence_factor,
@active_start_date,
@active_end_date,
@active_start_time,
@active_end_time
SELECT @retval = @@ERROR,
@schedule_id = @@IDENTITY
RETURN(@retval) -- 0 means success
END
GO
/**************************************************************/
/* SP_ATTACH_SCHEDULE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_attach_schedule ...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_attach_schedule')
AND (type = 'P')))
DROP PROCEDURE sp_attach_schedule
go
CREATE PROCEDURE sp_attach_schedule
(
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@schedule_id INT = NULL, -- Must provide either this or schedule_name
@schedule_name sysname = NULL, -- Must provide either this or schedule_id
@automatic_post BIT = 1 -- If 1 will post notifications to all tsx servers to that run this job
)
AS
BEGIN
DECLARE @retval INT
DECLARE @sched_owner_sid VARBINARY(85)
DECLARE @job_owner_sid VARBINARY(85)
SET NOCOUNT ON
-- Check that we can uniquely identify the job
EXECUTE @retval = msdb.dbo.sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check authority (only SQLServerAgent can add a schedule to a non-local job)
EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
IF (@retval <> 0)
RETURN(@retval)
-- Check that we can uniquely identify the schedule
EXECUTE @retval = msdb.dbo.sp_verify_schedule_identifiers @name_of_name_parameter = '@schedule_name',
@name_of_id_parameter = '@schedule_id',
@schedule_name = @schedule_name OUTPUT,
@schedule_id = @schedule_id OUTPUT,
@owner_sid = @sched_owner_sid OUTPUT,
@orig_server_id = NULL
IF (@retval <> 0)
RETURN(1) -- Failure
--Schedules can only be attached to a job if the caller owns the job
--or the caller is a sysadmin
IF ((@job_owner_sid <> SUSER_SID()) AND
(ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
BEGIN
RAISERROR(14377, -1, -1)
RETURN(1) -- Failure
END
-- If the record doesn't already exist create it
IF( NOT EXISTS(SELECT *
FROM msdb.dbo.sysjobschedules
WHERE (schedule_id = @schedule_id)
AND (job_id = @job_id)) )
BEGIN
INSERT INTO msdb.dbo.sysjobschedules (schedule_id, job_id)
SELECT @schedule_id, @job_id
SELECT @retval = @@ERROR
-- Notify SQLServerAgent of the change, but only if we know the job has been cached
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)))
BEGIN
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'S',
@job_id = @job_id,
@schedule_id = @schedule_id,
@action_type = N'I'
END
-- For a multi-server job, remind the user that they need to call sp_post_msx_operation
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id <> 0)))
-- sp_post_msx_operation will do nothing if the schedule isn't assigned to any tsx machines
IF (@automatic_post = 1)
EXECUTE sp_post_msx_operation @operation = 'INSERT', @object_type = 'JOB', @job_id = @job_id
ELSE
RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
-- update this job's subplan to point to this schedule
UPDATE msdb.dbo.sysmaintplan_subplans
SET schedule_id = @schedule_id
WHERE (job_id = @job_id)
AND (schedule_id IS NULL)
END
RETURN(@retval) -- 0 means success
END
GO
/**************************************************************/
/* SP_DETACH_SCHEDULE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_detach_schedule ...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_detach_schedule')
AND (type = 'P')))
DROP PROCEDURE sp_detach_schedule
go
CREATE PROCEDURE sp_detach_schedule
(
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@schedule_id INT = NULL, -- Must provide either this or schedule_name
@schedule_name sysname = NULL, -- Must provide either this or schedule_id
@delete_unused_schedule BIT = 0, -- Can optionally delete schedule if it isn't referenced.
-- The default is to keep schedules
@automatic_post BIT = 1 -- If 1 will post notifications to all tsx servers to that run this job
)
AS
BEGIN
DECLARE @retval INT
DECLARE @sched_owner_sid VARBINARY(85)
DECLARE @job_owner_sid VARBINARY(85)
SET NOCOUNT ON
-- Check that we can uniquely identify the job
EXECUTE @retval = msdb.dbo.sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check authority (only SQLServerAgent can add a schedule to a non-local job)
EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
IF (@retval <> 0)
RETURN(@retval)
-- Check that we can uniquely identify the schedule
EXECUTE @retval = msdb.dbo.sp_verify_schedule_identifiers @name_of_name_parameter = '@schedule_name',
@name_of_id_parameter = '@schedule_id',
@schedule_name = @schedule_name OUTPUT,
@schedule_id = @schedule_id OUTPUT,
@owner_sid = @sched_owner_sid OUTPUT,
@orig_server_id = NULL,
@job_id_filter = @job_id
IF (@retval <> 0)
RETURN(1) -- Failure
-- If the record doesn't exist raise an error
IF( NOT EXISTS(SELECT *
FROM msdb.dbo.sysjobschedules
WHERE (schedule_id = @schedule_id)
AND (job_id = @job_id)) )
BEGIN
RAISERROR(14374, 0, 1, @schedule_name, @job_name)
RETURN(1) -- Failure
END
ELSE
BEGIN
-- Permissions check:
-- If sysadmin continue (sysadmin can detach schedules they don't own)
-- Otherwise if the caller owns the job, we can detach it
-- Except If @delete_unused_schedule = 1 then the caller has to own both the job and the schedule
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
IF (@job_owner_sid = SUSER_SID())
BEGIN
IF ((@delete_unused_schedule = 1) AND (@sched_owner_sid <> SUSER_SID()))
BEGIN
-- Cannot delete the schedule
RAISERROR(14394, -1, -1)
RETURN(1) -- Failure
END
END
ELSE -- the caller is not sysadmin and it does not own the job -> throw
BEGIN
RAISERROR(14391, -1, -1)
RETURN(1) -- Failure
END
END
DELETE FROM msdb.dbo.sysjobschedules
WHERE (job_id = @job_id)
AND (schedule_id = @schedule_id)
SELECT @retval = @@ERROR
--delete the schedule if requested and it isn't referenced
IF(@retval = 0 AND @delete_unused_schedule = 1)
BEGIN
IF(NOT EXISTS(SELECT *
FROM msdb.dbo.sysjobschedules
WHERE (schedule_id = @schedule_id)))
BEGIN
DELETE FROM msdb.dbo.sysschedules
WHERE (schedule_id = @schedule_id)
END
END
-- Update the job's version/last-modified information
UPDATE msdb.dbo.sysjobs
SET version_number = version_number + 1,
date_modified = GETDATE()
WHERE (job_id = @job_id)
-- Notify SQLServerAgent of the change, but only if we know the job has been cached
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)))
BEGIN
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'S',
@job_id = @job_id,
@schedule_id = @schedule_id,
@action_type = N'D'
END
-- For a multi-server job, remind the user that they need to call sp_post_msx_operation
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id <> 0)))
-- sp_post_msx_operation will do nothing if the schedule isn't assigned to any tsx machines
IF (@automatic_post = 1)
EXECUTE sp_post_msx_operation @operation = 'INSERT', @object_type = 'JOB', @job_id = @job_id
ELSE
RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
-- set this job's subplan to the first schedule in sysjobschedules or NULL if there is none
UPDATE msdb.dbo.sysmaintplan_subplans
SET schedule_id = ( SELECT TOP(1) schedule_id
FROM msdb.dbo.sysjobschedules
WHERE (job_id = @job_id) )
WHERE (job_id = @job_id)
AND (schedule_id = @schedule_id)
END
RETURN(@retval) -- 0 means success
END
GO
/**************************************************************/
/* SP_UPDATE_REPLICATION_JOB_PARAMETER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_replication_job_parameter...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_update_replication_job_parameter')
AND (type = 'P')))
DROP PROCEDURE sp_update_replication_job_parameter
go
CREATE PROCEDURE sp_update_replication_job_parameter
@job_id UNIQUEIDENTIFIER,
@old_freq_type INT,
@new_freq_type INT
AS
BEGIN
DECLARE @category_id INT
DECLARE @pattern NVARCHAR(50)
DECLARE @patternidx INT
DECLARE @cmdline NVARCHAR(3200)
DECLARE @step_id INT
SET NOCOUNT ON
SELECT @pattern = N'%[-/][Cc][Oo][Nn][Tt][Ii][Nn][Uu][Oo][Uu][Ss]%'
-- Make sure that we are dealing with relevant replication jobs
SELECT @category_id = category_id
FROM msdb.dbo.sysjobs
WHERE (@job_id = job_id)
-- @category_id = 10 (REPL-Distribution), 13 (REPL-LogReader), 14 (REPL-Merge),
-- 19 (REPL-QueueReader)
IF @category_id IN (10, 13, 14, 19)
BEGIN
-- Adding the -Continuous parameter (non auto-start to auto-start)
IF ((@old_freq_type <> 0x40) AND (@new_freq_type = 0x40))
BEGIN
-- Use a cursor to handle multiple replication agent job steps
DECLARE step_cursor CURSOR LOCAL FOR
SELECT command, step_id
FROM msdb.dbo.sysjobsteps
WHERE (@job_id = job_id)
AND (UPPER(subsystem collate SQL_Latin1_General_CP1_CS_AS) IN (N'MERGE', N'LOGREADER', N'DISTRIBUTION', N'QUEUEREADER'))
OPEN step_cursor
FETCH step_cursor INTO @cmdline, @step_id
WHILE (@@FETCH_STATUS <> -1)
BEGIN
SELECT @patternidx = PATINDEX(@pattern, @cmdline)
-- Make sure that the -Continuous parameter has not been specified already
IF (@patternidx = 0)
BEGIN
SELECT @cmdline = @cmdline + N' -Continuous'
UPDATE msdb.dbo.sysjobsteps
SET command = @cmdline
WHERE (@job_id = job_id)
AND (@step_id = step_id)
END -- IF (@patternidx = 0)
FETCH NEXT FROM step_cursor into @cmdline, @step_id
END -- WHILE (@@FETCH_STATUS <> -1)
CLOSE step_cursor
DEALLOCATE step_cursor
END -- IF ((@old_freq_type...
-- Removing the -Continuous parameter (auto-start to non auto-start)
ELSE
IF ((@old_freq_type = 0x40) AND (@new_freq_type <> 0x40))
BEGIN
DECLARE step_cursor CURSOR LOCAL FOR
SELECT command, step_id
FROM msdb.dbo.sysjobsteps
WHERE (@job_id = job_id)
AND (UPPER(subsystem collate SQL_Latin1_General_CP1_CS_AS) IN (N'MERGE', N'LOGREADER', N'DISTRIBUTION', N'QUEUEREADER'))
OPEN step_cursor
FETCH step_cursor INTO @cmdline, @step_id
WHILE (@@FETCH_STATUS <> -1)
BEGIN
SELECT @patternidx = PATINDEX(@pattern, @cmdline)
IF (@patternidx <> 0)
BEGIN
-- Handle multiple instances of -Continuous in the commandline
WHILE (@patternidx <> 0)
BEGIN
SELECT @cmdline = STUFF(@cmdline, @patternidx, 11, N'')
IF (@patternidx > 1)
BEGIN
-- Remove the preceding space if -Continuous does not start at the beginning of the commandline
SELECT @cmdline = stuff(@cmdline, @patternidx - 1, 1, N'')
END
SELECT @patternidx = PATINDEX(@pattern, @cmdline)
END -- WHILE (@patternidx <> 0)
UPDATE msdb.dbo.sysjobsteps
SET command = @cmdline
WHERE (@job_id = job_id)
AND (@step_id = step_id)
END -- IF (@patternidx <> -1)
FETCH NEXT FROM step_cursor INTO @cmdline, @step_id
END -- WHILE (@@FETCH_STATUS <> -1)
CLOSE step_cursor
DEALLOCATE step_cursor
END -- ELSE IF ((@old_freq_type = 0x40)...
END -- IF @category_id IN (10, 13, 14)
RETURN 0
END
go
/**************************************************************/
/* SP_UPDATE_SCHEDULE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_schedule ...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_update_schedule')
AND (type = 'P')))
DROP PROCEDURE sp_update_schedule
go
CREATE PROCEDURE sp_update_schedule
(
@schedule_id INT = NULL, -- Must provide either this or schedule_name
@name sysname = NULL, -- Must provide either this or schedule_id
@new_name sysname = NULL,
@enabled TINYINT = NULL,
@freq_type INT = NULL,
@freq_interval INT = NULL,
@freq_subday_type INT = NULL,
@freq_subday_interval INT = NULL,
@freq_relative_interval INT = NULL,
@freq_recurrence_factor INT = NULL,
@active_start_date INT = NULL,
@active_end_date INT = NULL,
@active_start_time INT = NULL,
@active_end_time INT = NULL,
@owner_login_name sysname = NULL,
@automatic_post BIT = 1 -- If 1 will post notifications to all tsx servers to
-- update all jobs that use this schedule
)
AS
BEGIN
DECLARE @retval INT
DECLARE @owner_sid VARBINARY(85)
DECLARE @cur_owner_sid VARBINARY(85)
DECLARE @x_name sysname
DECLARE @enable_only_used INT
DECLARE @x_enabled TINYINT
DECLARE @x_freq_type INT
DECLARE @x_freq_interval INT
DECLARE @x_freq_subday_type INT
DECLARE @x_freq_subday_interval INT
DECLARE @x_freq_relative_interval INT
DECLARE @x_freq_recurrence_factor INT
DECLARE @x_active_start_date INT
DECLARE @x_active_end_date INT
DECLARE @x_active_start_time INT
DECLARE @x_active_end_time INT
DECLARE @schedule_uid UNIQUEIDENTIFIER
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
SELECT @new_name = LTRIM(RTRIM(@new_name))
SELECT @owner_login_name = LTRIM(RTRIM(@owner_login_name))
-- Turn [nullable] empty string parameters into NULLs
IF (@new_name = N'') SELECT @new_name = NULL
-- If the owner is supplied get the sid and check it
IF(@owner_login_name IS NOT NULL AND @owner_login_name <> '')
BEGIN
-- Get the sid for @owner_login_name SID
--force case insensitive comparation for NT users
SELECT @owner_sid = dbo.SQLAGENT_SUSER_SID(@owner_login_name)
-- Cannot proceed if @owner_login_name doesn't exist
IF(@owner_sid IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@owner_login_name', @owner_login_name)
RETURN(1) -- Failure
END
END
-- Check that we can uniquely identify the schedule. This only returns a schedule that is visible to this user
EXECUTE @retval = msdb.dbo.sp_verify_schedule_identifiers @name_of_name_parameter = '@name',
@name_of_id_parameter = '@schedule_id',
@schedule_name = @name OUTPUT,
@schedule_id = @schedule_id OUTPUT,
@owner_sid = @cur_owner_sid OUTPUT,
@orig_server_id = NULL
IF (@retval <> 0)
RETURN(1) -- Failure
-- Is @enable the only parameter used beside jobname and jobid?
IF ((@enabled IS NOT NULL) AND
(@new_name IS NULL) AND
(@freq_type IS NULL) AND
(@freq_interval IS NULL) AND
(@freq_subday_type IS NULL) AND
(@freq_subday_interval IS NULL) AND
(@freq_relative_interval IS NULL) AND
(@freq_recurrence_factor IS NULL) AND
(@active_start_date IS NULL) AND
(@active_end_date IS NULL) AND
(@active_start_time IS NULL) AND
(@active_end_time IS NULL) AND
(@owner_login_name IS NULL))
SELECT @enable_only_used = 1
ELSE
SELECT @enable_only_used = 0
-- Non-sysadmins can only update jobs schedules they own.
-- Members of SQLAgentReaderRole and SQLAgentOperatorRole can view job schedules,
-- but they should not be able to delete them
IF ((@cur_owner_sid <> SUSER_SID())
AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'),0) <> 1)
AND (@enable_only_used <> 1 OR ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) <> 1))
BEGIN
RAISERROR(14394, -1, -1)
RETURN(1) -- Failure
END
-- If the param @owner_login_name is null or doesn't get resolved by SUSER_SID() set it to the current owner of the schedule
if(@owner_sid IS NULL)
SELECT @owner_sid = @cur_owner_sid
-- Set the x_ (existing) variables
SELECT @x_name = name,
@x_enabled = enabled,
@x_freq_type = freq_type,
@x_freq_interval = freq_interval,
@x_freq_subday_type = freq_subday_type,
@x_freq_subday_interval = freq_subday_interval,
@x_freq_relative_interval = freq_relative_interval,
@x_freq_recurrence_factor = freq_recurrence_factor,
@x_active_start_date = active_start_date,
@x_active_end_date = active_end_date,
@x_active_start_time = active_start_time,
@x_active_end_time = active_end_time
FROM msdb.dbo.sysschedules
WHERE (schedule_id = @schedule_id )
-- Fill out the values for all non-supplied parameters from the existing values
IF (@new_name IS NULL) SELECT @new_name = @x_name
IF (@enabled IS NULL) SELECT @enabled = @x_enabled
IF (@freq_type IS NULL) SELECT @freq_type = @x_freq_type
IF (@freq_interval IS NULL) SELECT @freq_interval = @x_freq_interval
IF (@freq_subday_type IS NULL) SELECT @freq_subday_type = @x_freq_subday_type
IF (@freq_subday_interval IS NULL) SELECT @freq_subday_interval = @x_freq_subday_interval
IF (@freq_relative_interval IS NULL) SELECT @freq_relative_interval = @x_freq_relative_interval
IF (@freq_recurrence_factor IS NULL) SELECT @freq_recurrence_factor = @x_freq_recurrence_factor
IF (@active_start_date IS NULL) SELECT @active_start_date = @x_active_start_date
IF (@active_end_date IS NULL) SELECT @active_end_date = @x_active_end_date
IF (@active_start_time IS NULL) SELECT @active_start_time = @x_active_start_time
IF (@active_end_time IS NULL) SELECT @active_end_time = @x_active_end_time
-- Check schedule (frequency and owner) parameters
EXECUTE @retval = sp_verify_schedule @schedule_id = @schedule_id,
@name = @new_name,
@enabled = @enabled,
@freq_type = @freq_type,
@freq_interval = @freq_interval OUTPUT,
@freq_subday_type = @freq_subday_type OUTPUT,
@freq_subday_interval = @freq_subday_interval OUTPUT,
@freq_relative_interval = @freq_relative_interval OUTPUT,
@freq_recurrence_factor = @freq_recurrence_factor OUTPUT,
@active_start_date = @active_start_date OUTPUT,
@active_start_time = @active_start_time OUTPUT,
@active_end_date = @active_end_date OUTPUT,
@active_end_time = @active_end_time OUTPUT,
@owner_sid = @owner_sid
IF (@retval <> 0)
RETURN(1) -- Failure
-- Update the sysschedules table
UPDATE msdb.dbo.sysschedules
SET name = @new_name,
owner_sid = @owner_sid,
enabled = @enabled,
freq_type = @freq_type,
freq_interval = @freq_interval,
freq_subday_type = @freq_subday_type,
freq_subday_interval = @freq_subday_interval,
freq_relative_interval = @freq_relative_interval,
freq_recurrence_factor = @freq_recurrence_factor,
active_start_date = @active_start_date,
active_end_date = @active_end_date,
active_start_time = @active_start_time,
active_end_time = @active_end_time,
date_modified = GETDATE(),
version_number = version_number + 1
WHERE (schedule_id = @schedule_id)
SELECT @retval = @@error
-- update any job that has repl steps
DECLARE @job_id UNIQUEIDENTIFIER
DECLARE jobsschedule_cursor CURSOR LOCAL FOR
SELECT job_id
FROM msdb.dbo.sysjobschedules
WHERE (schedule_id = @schedule_id)
IF @x_freq_type <> @freq_type
BEGIN
OPEN jobsschedule_cursor
FETCH NEXT FROM jobsschedule_cursor INTO @job_id
WHILE (@@FETCH_STATUS = 0)
BEGIN
EXEC sp_update_replication_job_parameter @job_id = @job_id,
@old_freq_type = @x_freq_type,
@new_freq_type = @freq_type
FETCH NEXT FROM jobsschedule_cursor INTO @job_id
END
CLOSE jobsschedule_cursor
END
DEALLOCATE jobsschedule_cursor
-- Notify SQLServerAgent of the change if this is attached to a local job
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobschedules AS jsched
JOIN msdb.dbo.sysjobservers AS jsvr
ON jsched.job_id = jsvr.job_id
WHERE (jsched.schedule_id = @schedule_id)
AND (jsvr.server_id = 0)) )
BEGIN
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'S',
@schedule_id = @schedule_id,
@action_type = N'U'
END
-- Instruct the tsx servers to pick up the altered schedule
IF (@automatic_post = 1)
BEGIN
SELECT @schedule_uid = schedule_uid
FROM sysschedules
WHERE schedule_id = @schedule_id
IF(NOT @schedule_uid IS NULL)
BEGIN
-- sp_post_msx_operation will do nothing if the schedule isn't assigned to any tsx machines
EXECUTE @retval = sp_post_msx_operation @operation = 'INSERT', @object_type = 'SCHEDULE', @schedule_uid = @schedule_uid
END
END
RETURN(@retval) -- 0 means success
END
GO
/**************************************************************/
/* SP_DELETE_SCHEDULE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_schedule ...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_schedule')
AND (type = 'P')))
DROP PROCEDURE sp_delete_schedule
go
CREATE PROCEDURE sp_delete_schedule
(
@schedule_id INT = NULL, -- Must provide either this or schedule_name
@schedule_name sysname = NULL, -- Must provide either this or schedule_id
@force_delete bit = 0,
@automatic_post BIT = 1 -- If 1 will post notifications to all tsx servers to that run this schedule
)
AS
BEGIN
DECLARE @retval INT
DECLARE @owner_sid VARBINARY(85)
DECLARE @job_count INT
DECLARE @targ_server_id INT
SET NOCOUNT ON
--Get the owners sid
SELECT @job_count = 0
-- Check that we can uniquely identify the schedule. This only returns a schedule that is visible to this user
EXECUTE @retval = msdb.dbo.sp_verify_schedule_identifiers @name_of_name_parameter = '@schedule_name',
@name_of_id_parameter = '@schedule_id',
@schedule_name = @schedule_name OUTPUT,
@schedule_id = @schedule_id OUTPUT,
@owner_sid = @owner_sid OUTPUT,
@orig_server_id = NULL
IF (@retval <> 0)
RETURN(1) -- Failure
-- Non-sysadmins can only update jobs schedules they own.
-- Members of SQLAgentReaderRole and SQLAgentOperatorRole can view job schedules,
-- but they should not be able to delete them
IF ((@owner_sid <> SUSER_SID()) AND
(ISNULL(IS_SRVROLEMEMBER(N'sysadmin'),0) <> 1))
BEGIN
RAISERROR(14394, -1, -1)
RETURN(1) -- Failure
END
--check if there are jobs using this schedule
SELECT @job_count = count(*)
FROM sysjobschedules
WHERE (schedule_id = @schedule_id)
-- If we aren't force deleting the schedule make sure no jobs are using it
IF ((@force_delete = 0) AND (@job_count > 0))
BEGIN
RAISERROR(14372, -1, -1)
RETURN (1) -- Failure
END
-- Get the one of the terget server_id's.
-- Getting MIN(jsvr.server_id) works here because we are only interested in this ID
-- to determine if the schedule ID is for local jobs or MSX jobs.
-- Note, an MSX job can't be run on the local server
SELECT @targ_server_id = MIN(jsvr.server_id)
FROM msdb.dbo.sysjobschedules AS jsched
JOIN msdb.dbo.sysjobservers AS jsvr
ON jsched.job_id = jsvr.job_id
WHERE (jsched.schedule_id = @schedule_id)
--OK to delete the job - schedule link
DELETE sysjobschedules
WHERE schedule_id = @schedule_id
--OK to delete the schedule
DELETE sysschedules
WHERE schedule_id = @schedule_id
-- @targ_server_id would be null if no jobs use this schedule
IF (@targ_server_id IS NOT NULL)
BEGIN
-- Notify SQLServerAgent of the change but only if it the schedule was used by a local job
IF (@targ_server_id = 0)
BEGIN
-- Only send a notification if the schedule is force deleted. If it isn't force deleted
-- a notification would have already been sent while detaching the schedule (sp_detach_schedule)
IF (@force_delete = 1)
BEGIN
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'S',
@schedule_id = @schedule_id,
@action_type = N'D'
END
END
ELSE
BEGIN
-- Instruct the tsx servers to pick up the altered schedule
IF (@automatic_post = 1)
BEGIN
DECLARE @schedule_uid UNIQUEIDENTIFIER
SELECT @schedule_uid = schedule_uid
FROM sysschedules
WHERE schedule_id = @schedule_id
IF(NOT @schedule_uid IS NULL)
BEGIN
-- sp_post_msx_operation will do nothing if the schedule isn't assigned to any tsx machines
EXECUTE sp_post_msx_operation @operation = 'INSERT', @object_type = 'SCHEDULE', @schedule_uid = @schedule_uid
END
END
ELSE
RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
END
END
RETURN(@retval) -- 0 means success
END
GO
/**************************************************************/
/* SP_GET_JOBSTEP_DB_USERNAME */
/* */
/* NOTE: For NT login names this procedure can take several */
/* seconds to return as it hits the PDC/BDC. */
/* SQLServerAgent calls this at runtime. */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_get_jobstep_db_username...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_get_jobstep_db_username')
AND (type = 'P')))
DROP PROCEDURE sp_get_jobstep_db_username
go
CREATE PROCEDURE sp_get_jobstep_db_username
@database_name sysname,
@login_name sysname = NULL,
@username_in_targetdb sysname OUTPUT
AS
BEGIN
DECLARE @suser_sid_clause NVARCHAR(512)
-- Check the database name
IF (DB_ID(@database_name) IS NULL)
BEGIN
RAISERROR(14262, 16, 1, 'database', @database_name)
RETURN(1) -- Failure
END
-- Initialize return value
SELECT @username_in_targetdb = NULL
-- Make sure login name is never NULL
IF (@login_name IS NULL)
SELECT @login_name = SUSER_SNAME()
IF (@login_name IS NULL)
RETURN(1) -- Failure
-- Handle an NT login name
IF (@login_name LIKE N'%\%')
BEGIN
-- Special case...
IF (UPPER(@login_name collate SQL_Latin1_General_CP1_CS_AS) = N'NT AUTHORITY\SYSTEM')
SELECT @username_in_targetdb = N'dbo'
ELSE
SELECT @username_in_targetdb = @login_name
RETURN(0) -- Success
END
-- Handle a SQL login name
SELECT @suser_sid_clause = N'SUSER_SID(N' + QUOTENAME(@login_name, '''') + N')'
IF (SUSER_SID(@login_name) IS NULL)
RETURN(1) -- Failure
DECLARE @quoted_database_name NVARCHAR(258)
SELECT @quoted_database_name = QUOTENAME(@database_name, N'[')
DECLARE @temp_username TABLE (user_name sysname COLLATE database_default NOT NULL, is_aliased BIT)
-- 1) Look for the user name of the current login in the target database
INSERT INTO @temp_username
EXECUTE (N'SET NOCOUNT ON
SELECT name, isaliased
FROM '+ @quoted_database_name + N'.[dbo].[sysusers]
WHERE (sid = ' + @suser_sid_clause + N')
AND (hasdbaccess = 1)')
-- 2) Look for the alias user name of the current login in the target database
IF (EXISTS (SELECT *
FROM @temp_username
WHERE (is_aliased = 1)))
BEGIN
DELETE FROM @temp_username
INSERT INTO @temp_username
EXECUTE (N'SET NOCOUNT ON
SELECT name, 0
FROM '+ @quoted_database_name + N'.[dbo].[sysusers]
WHERE uid = (SELECT altuid
FROM ' + @quoted_database_name + N'.[dbo].[sysusers]
WHERE (sid = ' + @suser_sid_clause + N'))
AND (hasdbaccess = 1)')
END
-- 3) Look for the guest user name in the target database
IF (NOT EXISTS (SELECT *
FROM @temp_username))
INSERT INTO @temp_username
EXECUTE (N'SET NOCOUNT ON
SELECT name, 0
FROM '+ @quoted_database_name + N'.[dbo].[sysusers]
WHERE (name = N''guest'')
AND (hasdbaccess = 1)')
SELECT @username_in_targetdb = user_name
FROM @temp_username
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_VERIFY_JOBSTEP */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_jobstep...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_jobstep')
AND (type = 'P')))
DROP PROCEDURE sp_verify_jobstep
go
CREATE PROCEDURE sp_verify_jobstep
@job_id UNIQUEIDENTIFIER,
@step_id INT,
@step_name sysname,
@subsystem NVARCHAR(40),
@command NVARCHAR(max),
@server sysname,
@on_success_action TINYINT,
@on_success_step_id INT,
@on_fail_action TINYINT,
@on_fail_step_id INT,
@os_run_priority INT,
@database_name sysname OUTPUT,
@database_user_name sysname OUTPUT,
@flags INT,
@output_file_name NVARCHAR(200),
@proxy_id INT
AS
BEGIN
DECLARE @max_step_id INT
DECLARE @retval INT
DECLARE @valid_values VARCHAR(50)
DECLARE @database_name_temp NVARCHAR(258)
DECLARE @database_user_name_temp NVARCHAR(256)
DECLARE @temp_command NVARCHAR(max)
DECLARE @iPos INT
DECLARE @create_count INT
DECLARE @destroy_count INT
DECLARE @is_olap_subsystem BIT
DECLARE @owner_sid VARBINARY(85)
DECLARE @owner_name sysname
-- Remove any leading/trailing spaces from parameters
SELECT @subsystem = LTRIM(RTRIM(@subsystem))
SELECT @server = LTRIM(RTRIM(@server))
SELECT @output_file_name = LTRIM(RTRIM(@output_file_name))
-- Get current maximum step id
SELECT @max_step_id = ISNULL(MAX(step_id), 0)
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
-- Check step id
IF (@step_id < 1) OR (@step_id > @max_step_id + 1)
BEGIN
SELECT @valid_values = '1..' + CONVERT(VARCHAR, @max_step_id + 1)
RAISERROR(14266, -1, -1, '@step_id', @valid_values)
RETURN(1) -- Failure
END
-- Check subsystem
EXECUTE @retval = sp_verify_subsystem @subsystem
IF (@retval <> 0)
RETURN(1) -- Failure
--check if proxy is allowed for this subsystem for current user
IF (@proxy_id IS NOT NULL)
BEGIN
--get the job owner
SELECT @owner_sid = owner_sid FROM sysjobs
WHERE job_id = @job_id
IF @owner_sid = 0xFFFFFFFF
BEGIN
--ask to verify for the special account
EXECUTE @retval = sp_verify_proxy_permissions
@subsystem_name = @subsystem,
@proxy_id = @proxy_id,
@name = NULL,
@raise_error = 1,
@allow_disable_proxy = 1,
@verify_special_account = 1
IF (@retval <> 0)
RETURN(1) -- Failure
END
ELSE
BEGIN
SELECT @owner_name = SUSER_SNAME(@owner_sid)
EXECUTE @retval = sp_verify_proxy_permissions
@subsystem_name = @subsystem,
@proxy_id = @proxy_id,
@name = @owner_name,
@raise_error = 1,
@allow_disable_proxy = 1
IF (@retval <> 0)
RETURN(1) -- Failure
END
END
--Only sysadmin can specify @output_file_name
IF (@output_file_name IS NOT NULL) AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(14582, -1, -1)
RETURN(1) -- Failure
END
--Determmine if this is a olap subsystem jobstep
IF ( UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) in (N'ANALYSISQUERY', N'ANALYSISCOMMAND') )
SELECT @is_olap_subsystem = 1
ELSE
SELECT @is_olap_subsystem = 0
-- Check command length
-- not necessary now, command can be any length
/*
IF ((DATALENGTH(@command) / 2) > 3200)
BEGIN
RAISERROR(14250, 16, 1, '@command', 3200)
RETURN(1) -- Failure
END
*/
-- For a VBScript command, check that object creations are paired with object destructions
IF ((UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'ACTIVESCRIPTING') AND (@database_name = N'VBScript'))
BEGIN
SET @temp_command = @command
SELECT @create_count = 0
SELECT @iPos = PATINDEX('%[Cc]reate[Oo]bject[ (]%', @temp_command)
WHILE(@iPos > 0)
BEGIN
SELECT @temp_command = SUBSTRING(@temp_command, @iPos + 1, DATALENGTH(@temp_command) / 2)
SELECT @iPos = PATINDEX('%[Cc]reate[Oo]bject[ (]%', @temp_command)
SELECT @create_count = @create_count + 1
END
-- restore @temp_command for next loop
SET @temp_command = @command
SELECT @destroy_count = 0
SELECT @iPos = PATINDEX('%[Ss]et %=%[Nn]othing%', @temp_command)
WHILE(@iPos > 0)
BEGIN
SELECT @temp_command = SUBSTRING(@temp_command, @iPos + 1, DATALENGTH(@temp_command) / 2)
SELECT @iPos = PATINDEX('%[Ss]et %=%[Nn]othing%', @temp_command)
SELECT @destroy_count = @destroy_count + 1
END
IF(@create_count > @destroy_count)
BEGIN
RAISERROR(14277, -1, -1)
RETURN(1) -- Failure
END
END
-- Check step name
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND (step_name = @step_name)))
BEGIN
RAISERROR(14261, -1, -1, '@step_name', @step_name)
RETURN(1) -- Failure
END
-- Check on-success action/step
IF (@on_success_action <> 1) AND -- Quit Qith Success
(@on_success_action <> 2) AND -- Quit Qith Failure
(@on_success_action <> 3) AND -- Goto Next Step
(@on_success_action <> 4) -- Goto Step
BEGIN
RAISERROR(14266, -1, -1, '@on_success_action', '1, 2, 3, 4')
RETURN(1) -- Failure
END
IF (@on_success_action = 4) AND
((@on_success_step_id < 1) OR (@on_success_step_id = @step_id))
BEGIN
-- NOTE: We allow forward references to non-existant steps to prevent the user from
-- having to make a second update pass to fix up the flow
RAISERROR(14235, -1, -1, '@on_success_step', @step_id)
RETURN(1) -- Failure
END
-- Check on-fail action/step
IF (@on_fail_action <> 1) AND -- Quit With Success
(@on_fail_action <> 2) AND -- Quit With Failure
(@on_fail_action <> 3) AND -- Goto Next Step
(@on_fail_action <> 4) -- Goto Step
BEGIN
RAISERROR(14266, -1, -1, '@on_failure_action', '1, 2, 3, 4')
RETURN(1) -- Failure
END
IF (@on_fail_action = 4) AND
((@on_fail_step_id < 1) OR (@on_fail_step_id = @step_id))
BEGIN
-- NOTE: We allow forward references to non-existant steps to prevent the user from
-- having to make a second update pass to fix up the flow
RAISERROR(14235, -1, -1, '@on_failure_step', @step_id)
RETURN(1) -- Failure
END
-- Warn the user about forward references
IF ((@on_success_action = 4) AND (@on_success_step_id > @max_step_id))
RAISERROR(14236, 0, 1, '@on_success_step_id')
IF ((@on_fail_action = 4) AND (@on_fail_step_id > @max_step_id))
RAISERROR(14236, 0, 1, '@on_fail_step_id')
--Special case the olap subsystem. It can have any server name.
--Default it to the local server if @server is null
IF(@is_olap_subsystem = 1)
BEGIN
IF(@server IS NULL)
BEGIN
--TODO: needs error better message ? >> 'Specify the OLAP server name in the %s parameter'
--Must specify the olap server name
RAISERROR(14262, -1, -1, '@server', @server)
RETURN(1) -- Failure
END
END
ELSE
BEGIN
-- Check server (this is the replication server, NOT the job-target server)
IF (@server IS NOT NULL) AND (NOT EXISTS (SELECT *
FROM master.dbo.sysservers
WHERE (UPPER(srvname) = UPPER(@server))))
BEGIN
RAISERROR(14234, -1, -1, '@server', 'sp_helpserver')
RETURN(1) -- Failure
END
END
-- Check run priority: must be a valid value to pass to SetThreadPriority:
-- [-15 = IDLE, -1 = BELOW_NORMAL, 0 = NORMAL, 1 = ABOVE_NORMAL, 15 = TIME_CRITICAL]
IF (@os_run_priority NOT IN (-15, -1, 0, 1, 15))
BEGIN
RAISERROR(14266, -1, -1, '@os_run_priority', '-15, -1, 0, 1, 15')
RETURN(1) -- Failure
END
-- Check flags
IF ((@flags < 0) OR (@flags > 114))
BEGIN
RAISERROR(14266, -1, -1, '@flags', '0..114')
RETURN(1) -- Failure
END
-- @flags=4 is valid only for TSQL subsystem
IF (((@flags & 4) <> 0) AND (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('TSQL')))
BEGIN
RAISERROR(14545, -1, -1, '@flags', @subsystem)
RETURN(1) -- Failure
END
-- values 8 and 16 for @flags cannot be combined
IF (((@flags & 8) <> 0) AND ((@flags & 16) <> 0))
BEGIN
RAISERROR(14545, -1, -1, '@flags', @subsystem)
RETURN(1) -- Failure
END
IF (((@flags & 64) <> 0) AND (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('CMDEXEC')))
BEGIN
RAISERROR(14545, -1, -1, '@flags', @subsystem)
RETURN(1) -- Failure
END
-- Check output file
IF (@output_file_name IS NOT NULL) AND (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('TSQL', 'CMDEXEC', 'ANALYSISQUERY', 'ANALYSISCOMMAND', 'SSIS', 'POWERSHELL' ))
BEGIN
RAISERROR(14545, -1, -1, '@output_file_name', @subsystem)
RETURN(1) -- Failure
END
-- Check writing to table flags
-- Note: explicit check for null is required here
IF (@flags IS NOT NULL) AND (((@flags & 8) <> 0) OR ((@flags & 16) <> 0)) AND (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('TSQL', 'CMDEXEC', 'ANALYSISQUERY', 'ANALYSISCOMMAND', 'SSIS', 'POWERSHELL' ))
BEGIN
RAISERROR(14545, -1, -1, '@flags', @subsystem)
RETURN(1) -- Failure
END
-- For CmdExec steps database-name and database-user-name should both be null
IF (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'CMDEXEC')
SELECT @database_name = NULL,
@database_user_name = NULL
-- For non-TSQL steps, database-user-name should be null
IF (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) <> 'TSQL')
SELECT @database_user_name = NULL
-- For a TSQL step, get (and check) the username of the caller in the target database.
IF (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = 'TSQL')
BEGIN
SET NOCOUNT ON
-- But first check if remote server name has been supplied
IF (@server IS NOT NULL)
SELECT @server = NULL
-- Default database to 'master' if not supplied
IF (LTRIM(RTRIM(@database_name)) IS NULL)
SELECT @database_name = N'master'
-- Check the database (although this is no guarantee that @database_user_name can access it)
IF (DB_ID(@database_name) IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@database_name', @database_name)
RETURN(1) -- Failure
END
SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))
-- Only if a SysAdmin is creating the job can the database user name be non-NULL [since only
-- SysAdmin's can call SETUSER].
-- NOTE: In this case we don't try to validate the user name (it's too costly to do so)
-- so if it's bad we'll get a runtime error when the job executes.
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
BEGIN
-- If this is a multi-server job then @database_user_name must be null
IF (@database_user_name IS NOT NULL)
BEGIN
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobs sj,
msdb.dbo.sysjobservers sjs
WHERE (sj.job_id = sjs.job_id)
AND (sj.job_id = @job_id)
AND (sjs.server_id <> 0)))
BEGIN
RAISERROR(14542, -1, -1, N'database_user_name')
RETURN(1) -- Failure
END
END
-- For a SQL-user, check if it exists
IF (@database_user_name NOT LIKE N'%\%')
BEGIN
SELECT @database_user_name_temp = replace(@database_user_name, N'''', N'''''')
SELECT @database_name_temp = QUOTENAME(@database_name)
EXECUTE(N'DECLARE @ret INT
SELECT @ret = COUNT(*)
FROM ' + @database_name_temp + N'.dbo.sysusers
WHERE (name = N''' + @database_user_name_temp + N''')
HAVING (COUNT(*) > 0)')
IF (@@ROWCOUNT = 0)
BEGIN
RAISERROR(14262, -1, -1, '@database_user_name', @database_user_name)
RETURN(1) -- Failure
END
END
END
ELSE
SELECT @database_user_name = NULL
END -- End of TSQL property verification
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_ADD_JOBSTEP_INTERNAL */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_jobstep_internal...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_jobstep_internal')
AND (type = 'P')))
DROP PROCEDURE dbo.sp_add_jobstep_internal
go
CREATE PROCEDURE dbo.sp_add_jobstep_internal
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@step_id INT = NULL, -- The proc assigns a default
@step_name sysname,
@subsystem NVARCHAR(40) = N'TSQL',
@command NVARCHAR(max) = NULL,
@additional_parameters NVARCHAR(max) = NULL,
@cmdexec_success_code INT = 0,
@on_success_action TINYINT = 1, -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step
@on_success_step_id INT = 0,
@on_fail_action TINYINT = 2, -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step
@on_fail_step_id INT = 0,
@server sysname = NULL,
@database_name sysname = NULL,
@database_user_name sysname = NULL,
@retry_attempts INT = 0, -- No retries
@retry_interval INT = 0, -- 0 minute interval
@os_run_priority INT = 0, -- -15 = Idle, -1 = Below Normal, 0 = Normal, 1 = Above Normal, 15 = Time Critical)
@output_file_name NVARCHAR(200) = NULL,
@flags INT = 0, -- 0 = Normal,
-- 1 = Encrypted command (read only),
-- 2 = Append output files (if any),
-- 4 = Write TSQL step output to step history
-- 8 = Write log to table (overwrite existing history)
-- 16 = Write log to table (append to existing history)
-- 32 = Write all output to job history
-- 64 = Create a Windows event to use as a signal for the Cmd jobstep to abort
@proxy_id int = NULL,
@proxy_name sysname = NULL,
-- mutual exclusive; must specify only one of above 2 parameters to
-- identify the proxy.
@step_uid UNIQUEIDENTIFIER = NULL OUTPUT
AS
BEGIN
DECLARE @retval INT
DECLARE @max_step_id INT
DECLARE @job_owner_sid VARBINARY(85)
DECLARE @subsystem_id INT
DECLARE @auto_proxy_name sysname
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @step_name = LTRIM(RTRIM(@step_name))
SELECT @subsystem = LTRIM(RTRIM(@subsystem))
SELECT @server = LTRIM(RTRIM(@server))
SELECT @database_name = LTRIM(RTRIM(@database_name))
SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))
SELECT @output_file_name = LTRIM(RTRIM(@output_file_name))
SELECT @proxy_name = LTRIM(RTRIM(@proxy_name))
-- Turn [nullable] empty string parameters into NULLs
IF (@server = N'') SELECT @server = NULL
IF (@database_name = N'') SELECT @database_name = NULL
IF (@database_user_name = N'') SELECT @database_user_name = NULL
IF (@output_file_name = N'') SELECT @output_file_name = NULL
IF (@proxy_name = N'') SELECT @proxy_name = NULL
-- Check authority (only SQLServerAgent can add a step to a non-local job)
EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
IF (@retval <> 0)
RETURN(@retval)
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1) AND
(SUSER_SID() <> @job_owner_sid))
BEGIN
RAISERROR(14525, -1, -1)
RETURN(1) -- Failure
END
-- check proxy identifiers only if a proxy has been provided
IF (@proxy_id IS NOT NULL) or (@proxy_name IS NOT NULL)
BEGIN
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Default step id (if not supplied)
IF (@step_id IS NULL)
BEGIN
SELECT @step_id = ISNULL(MAX(step_id), 0) + 1
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
END
-- Check parameters
EXECUTE @retval = sp_verify_jobstep @job_id,
@step_id,
@step_name,
@subsystem,
@command,
@server,
@on_success_action,
@on_success_step_id,
@on_fail_action,
@on_fail_step_id,
@os_run_priority,
@database_name OUTPUT,
@database_user_name OUTPUT,
@flags,
@output_file_name,
@proxy_id
IF (@retval <> 0)
RETURN(1) -- Failure
-- Get current maximum step id
SELECT @max_step_id = ISNULL(MAX(step_id), 0)
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
DECLARE @TranCounter INT;
SET @TranCounter = @@TRANCOUNT;
IF @TranCounter = 0
BEGIN
-- start our own transaction if there is no outer transaction
BEGIN TRANSACTION;
END
-- Modify database.
BEGIN TRY
-- Update the job's version/last-modified information
UPDATE msdb.dbo.sysjobs
SET version_number = version_number + 1,
date_modified = GETDATE()
WHERE (job_id = @job_id)
-- Adjust step id's (unless the new step is being inserted at the 'end')
-- NOTE: We MUST do this before inserting the step.
IF (@step_id <= @max_step_id)
BEGIN
UPDATE msdb.dbo.sysjobsteps
SET step_id = step_id + 1
WHERE (step_id >= @step_id)
AND (job_id = @job_id)
-- Clean up OnSuccess/OnFail references
UPDATE msdb.dbo.sysjobsteps
SET on_success_step_id = on_success_step_id + 1
WHERE (on_success_step_id >= @step_id)
AND (job_id = @job_id)
UPDATE msdb.dbo.sysjobsteps
SET on_fail_step_id = on_fail_step_id + 1
WHERE (on_fail_step_id >= @step_id)
AND (job_id = @job_id)
UPDATE msdb.dbo.sysjobsteps
SET on_success_step_id = 0,
on_success_action = 1 -- Quit With Success
WHERE (on_success_step_id = @step_id)
AND (job_id = @job_id)
UPDATE msdb.dbo.sysjobsteps
SET on_fail_step_id = 0,
on_fail_action = 2 -- Quit With Failure
WHERE (on_fail_step_id = @step_id)
AND (job_id = @job_id)
END
SELECT @step_uid = NEWID()
-- Insert the step
INSERT INTO msdb.dbo.sysjobsteps
(job_id,
step_id,
step_name,
subsystem,
command,
flags,
additional_parameters,
cmdexec_success_code,
on_success_action,
on_success_step_id,
on_fail_action,
on_fail_step_id,
server,
database_name,
database_user_name,
retry_attempts,
retry_interval,
os_run_priority,
output_file_name,
last_run_outcome,
last_run_duration,
last_run_retries,
last_run_date,
last_run_time,
proxy_id,
step_uid)
VALUES (@job_id,
@step_id,
@step_name,
@subsystem,
@command,
@flags,
@additional_parameters,
@cmdexec_success_code,
@on_success_action,
@on_success_step_id,
@on_fail_action,
@on_fail_step_id,
@server,
@database_name,
@database_user_name,
@retry_attempts,
@retry_interval,
@os_run_priority,
@output_file_name,
0,
0,
0,
0,
0,
@proxy_id,
@step_uid)
IF @TranCounter = 0
BEGIN
-- start our own transaction if there is no outer transaction
COMMIT TRANSACTION;
END
END TRY
BEGIN CATCH
-- Prepare tp echo error information to the caller.
DECLARE @ErrorMessage NVARCHAR(400)
DECLARE @ErrorSeverity INT
DECLARE @ErrorState INT
SELECT @ErrorMessage = ERROR_MESSAGE()
SELECT @ErrorSeverity = ERROR_SEVERITY()
SELECT @ErrorState = ERROR_STATE()
IF @TranCounter = 0
BEGIN
-- Transaction started in procedure.
-- Roll back complete transaction.
ROLLBACK TRANSACTION;
END
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
)
RETURN (1)
END CATCH
-- Make sure that SQLServerAgent refreshes the job if the 'Has Steps' property has changed
IF ((SELECT COUNT(*)
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)) = 1)
BEGIN
-- NOTE: We only notify SQLServerAgent if we know the job has been cached
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)))
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',
@job_id = @job_id,
@action_type = N'U'
END
-- For a multi-server job, push changes to the target servers
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id <> 0)))
BEGIN
EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_ADD_JOBSTEP */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_jobstep...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_jobstep')
AND (type = 'P')))
DROP PROCEDURE dbo.sp_add_jobstep
go
CREATE PROCEDURE dbo.sp_add_jobstep
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@step_id INT = NULL, -- The proc assigns a default
@step_name sysname,
@subsystem NVARCHAR(40) = N'TSQL',
@command NVARCHAR(max) = NULL,
@additional_parameters NVARCHAR(max) = NULL,
@cmdexec_success_code INT = 0,
@on_success_action TINYINT = 1, -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step
@on_success_step_id INT = 0,
@on_fail_action TINYINT = 2, -- 1 = Quit With Success, 2 = Quit With Failure, 3 = Goto Next Step, 4 = Goto Step
@on_fail_step_id INT = 0,
@server sysname = NULL,
@database_name sysname = NULL,
@database_user_name sysname = NULL,
@retry_attempts INT = 0, -- No retries
@retry_interval INT = 0, -- 0 minute interval
@os_run_priority INT = 0, -- -15 = Idle, -1 = Below Normal, 0 = Normal, 1 = Above Normal, 15 = Time Critical)
@output_file_name NVARCHAR(200) = NULL,
@flags INT = 0, -- 0 = Normal,
-- 1 = Encrypted command (read only),
-- 2 = Append output files (if any),
-- 4 = Write TSQL step output to step history,
-- 8 = Write log to table (overwrite existing history),
-- 16 = Write log to table (append to existing history)
-- 32 = Write all output to job history
-- 64 = Create a Windows event to use as a signal for the Cmd jobstep to abort
@proxy_id INT = NULL,
@proxy_name sysname = NULL,
-- mutual exclusive; must specify only one of above 2 parameters to
-- identify the proxy.
@step_uid UNIQUEIDENTIFIER = NULL OUTPUT
AS
BEGIN
DECLARE @retval INT
SET NOCOUNT ON
-- Only sysadmin's or db_owner's of msdb can add replication job steps directly
IF (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) IN
(N'DISTRIBUTION',
N'SNAPSHOT',
N'LOGREADER',
N'MERGE',
N'QUEUEREADER'))
BEGIN
IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR
(ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR
(UPPER(USER_NAME() collate SQL_Latin1_General_CP1_CS_AS) = N'DBO'))
BEGIN
RAISERROR(14260, -1, -1)
RETURN(1) -- Failure
END
END
--Only sysadmin can specify @database_user_name
IF (@database_user_name IS NOT NULL) AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(14583, -1, -1)
RETURN(1) -- Failure
END
-- Make sure Dts is translated into new subsystem's name SSIS
IF UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'DTS'
BEGIN
SET @subsystem = N'SSIS'
END
EXECUTE @retval = dbo.sp_add_jobstep_internal @job_id = @job_id,
@job_name = @job_name,
@step_id = @step_id,
@step_name = @step_name,
@subsystem = @subsystem,
@command = @command,
@additional_parameters = @additional_parameters,
@cmdexec_success_code = @cmdexec_success_code,
@on_success_action = @on_success_action,
@on_success_step_id = @on_success_step_id,
@on_fail_action = @on_fail_action,
@on_fail_step_id = @on_fail_step_id,
@server = @server,
@database_name = @database_name,
@database_user_name = @database_user_name,
@retry_attempts = @retry_attempts,
@retry_interval = @retry_interval,
@os_run_priority = @os_run_priority,
@output_file_name = @output_file_name,
@flags = @flags,
@proxy_id = @proxy_id,
@proxy_name = @proxy_name,
@step_uid = @step_uid OUTPUT
RETURN(@retval)
END
GO
/**************************************************************/
/* SP_UPDATE_JOBSTEP */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_jobstep...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_update_jobstep')
AND (type = 'P')))
DROP PROCEDURE sp_update_jobstep
go
CREATE PROCEDURE sp_update_jobstep
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Not updatable (provided for identification purposes only)
@step_id INT, -- Not updatable (provided for identification purposes only)
@step_name sysname = NULL,
@subsystem NVARCHAR(40) = NULL,
@command NVARCHAR(max) = NULL,
@additional_parameters NVARCHAR(max) = NULL,
@cmdexec_success_code INT = NULL,
@on_success_action TINYINT = NULL,
@on_success_step_id INT = NULL,
@on_fail_action TINYINT = NULL,
@on_fail_step_id INT = NULL,
@server sysname = NULL,
@database_name sysname = NULL,
@database_user_name sysname = NULL,
@retry_attempts INT = NULL,
@retry_interval INT = NULL,
@os_run_priority INT = NULL,
@output_file_name NVARCHAR(200) = NULL,
@flags INT = NULL,
@proxy_id int = NULL,
@proxy_name sysname = NULL
-- mutual exclusive; must specify only one of above 2 parameters to
-- identify the proxy.
AS
BEGIN
DECLARE @retval INT
DECLARE @os_run_priority_code INT
DECLARE @step_id_as_char VARCHAR(10)
DECLARE @new_step_name sysname
DECLARE @x_step_name sysname
DECLARE @x_subsystem NVARCHAR(40)
DECLARE @x_command NVARCHAR(max)
DECLARE @x_flags INT
DECLARE @x_cmdexec_success_code INT
DECLARE @x_on_success_action TINYINT
DECLARE @x_on_success_step_id INT
DECLARE @x_on_fail_action TINYINT
DECLARE @x_on_fail_step_id INT
DECLARE @x_server sysname
DECLARE @x_database_name sysname
DECLARE @x_database_user_name sysname
DECLARE @x_retry_attempts INT
DECLARE @x_retry_interval INT
DECLARE @x_os_run_priority INT
DECLARE @x_output_file_name NVARCHAR(200)
DECLARE @x_proxy_id INT
DECLARE @x_last_run_outcome TINYINT -- Not updatable (but may be in future)
DECLARE @x_last_run_duration INT -- Not updatable (but may be in future)
DECLARE @x_last_run_retries INT -- Not updatable (but may be in future)
DECLARE @x_last_run_date INT -- Not updatable (but may be in future)
DECLARE @x_last_run_time INT -- Not updatable (but may be in future)
DECLARE @new_proxy_id INT
DECLARE @subsystem_id INT
DECLARE @auto_proxy_name sysname
DECLARE @job_owner_sid VARBINARY(85)
SET NOCOUNT ON
SELECT @new_proxy_id = NULL
-- Remove any leading/trailing spaces from parameters
SELECT @step_name = LTRIM(RTRIM(@step_name))
SELECT @subsystem = LTRIM(RTRIM(@subsystem))
SELECT @command = LTRIM(RTRIM(@command))
SELECT @server = LTRIM(RTRIM(@server))
SELECT @database_name = LTRIM(RTRIM(@database_name))
SELECT @database_user_name = LTRIM(RTRIM(@database_user_name))
SELECT @output_file_name = LTRIM(RTRIM(@output_file_name))
SELECT @proxy_name = LTRIM(RTRIM(@proxy_name))
-- Make sure Dts is translated into new subsystem's name SSIS
IF (@subsystem IS NOT NULL AND UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'DTS')
BEGIN
SET @subsystem = N'SSIS'
END
-- Only sysadmin's or db_owner's of msdb can directly change
-- an existing job step to use one of the replication
-- subsystems
IF (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) IN
(N'DISTRIBUTION',
N'SNAPSHOT',
N'LOGREADER',
N'MERGE',
N'QUEUEREADER'))
BEGIN
IF NOT ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR
(ISNULL(IS_MEMBER(N'db_owner'), 0) = 1) OR
(UPPER(USER_NAME() collate SQL_Latin1_General_CP1_CS_AS) = N'DBO'))
BEGIN
RAISERROR(14260, -1, -1)
RETURN(1) -- Failure
END
END
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check permissions beyond what's checked by the sysjobs_view
-- SQLAgentReader and SQLAgentOperator roles that can see all jobs
-- cannot modify jobs they do not own
IF (@job_owner_sid <> SUSER_SID() -- does not own the job
AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)) -- is not sysadmin
BEGIN
RAISERROR(14525, -1, -1);
RETURN(1) -- Failure
END
-- Check that the step exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND (step_id = @step_id)))
BEGIN
SELECT @step_id_as_char = CONVERT(VARCHAR(10), @step_id)
RAISERROR(14262, -1, -1, '@step_id', @step_id_as_char)
RETURN(1) -- Failure
END
-- check proxy identifiers only if a proxy has been provided
-- @proxy_name = N'' is a special case to allow change of an existing proxy with NULL
IF (@proxy_id IS NOT NULL) OR (@proxy_name IS NOT NULL AND @proxy_name <> N'')
BEGIN
EXECUTE @retval = sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
SELECT @new_proxy_id = @proxy_id
END
-- Check authority (only SQLServerAgent can modify a step of a non-local job)
EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
IF (@retval <> 0)
RETURN(@retval)
-- Set the x_ (existing) variables
SELECT @x_step_name = step_name,
@x_subsystem = subsystem,
@x_command = command,
@x_flags = flags,
@x_cmdexec_success_code = cmdexec_success_code,
@x_on_success_action = on_success_action,
@x_on_success_step_id = on_success_step_id,
@x_on_fail_action = on_fail_action,
@x_on_fail_step_id = on_fail_step_id,
@x_server = server,
@x_database_name = database_name,
@x_database_user_name = database_user_name,
@x_retry_attempts = retry_attempts,
@x_retry_interval = retry_interval,
@x_os_run_priority = os_run_priority,
@x_output_file_name = output_file_name,
@x_proxy_id = proxy_id,
@x_last_run_outcome = last_run_outcome,
@x_last_run_duration = last_run_duration,
@x_last_run_retries = last_run_retries,
@x_last_run_date = last_run_date,
@x_last_run_time = last_run_time
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND (step_id = @step_id)
IF ((@step_name IS NOT NULL) AND (@step_name <> @x_step_name))
SELECT @new_step_name = @step_name
-- Fill out the values for all non-supplied parameters from the existing values
IF (@step_name IS NULL) SELECT @step_name = @x_step_name
IF (@subsystem IS NULL) SELECT @subsystem = @x_subsystem
IF (@command IS NULL) SELECT @command = @x_command
IF (@flags IS NULL) SELECT @flags = @x_flags
IF (@cmdexec_success_code IS NULL) SELECT @cmdexec_success_code = @x_cmdexec_success_code
IF (@on_success_action IS NULL) SELECT @on_success_action = @x_on_success_action
IF (@on_success_step_id IS NULL) SELECT @on_success_step_id = @x_on_success_step_id
IF (@on_fail_action IS NULL) SELECT @on_fail_action = @x_on_fail_action
IF (@on_fail_step_id IS NULL) SELECT @on_fail_step_id = @x_on_fail_step_id
IF (@server IS NULL) SELECT @server = @x_server
IF (@database_name IS NULL) SELECT @database_name = @x_database_name
IF (@database_user_name IS NULL) SELECT @database_user_name = @x_database_user_name
IF (@retry_attempts IS NULL) SELECT @retry_attempts = @x_retry_attempts
IF (@retry_interval IS NULL) SELECT @retry_interval = @x_retry_interval
IF (@os_run_priority IS NULL) SELECT @os_run_priority = @x_os_run_priority
IF (@output_file_name IS NULL) SELECT @output_file_name = @x_output_file_name
IF (@proxy_id IS NULL) SELECT @new_proxy_id = @x_proxy_id
--if an empty proxy_name is supplied the proxy is removed
IF @proxy_name = N'' SELECT @new_proxy_id = NULL
-- Turn [nullable] empty string parameters into NULLs
IF (@command = N'') SELECT @command = NULL
IF (@server = N'') SELECT @server = NULL
IF (@database_name = N'') SELECT @database_name = NULL
IF (@database_user_name = N'') SELECT @database_user_name = NULL
IF (@output_file_name = N'') SELECT @output_file_name = NULL
-- Check new values
EXECUTE @retval = sp_verify_jobstep @job_id,
@step_id,
@new_step_name,
@subsystem,
@command,
@server,
@on_success_action,
@on_success_step_id,
@on_fail_action,
@on_fail_step_id,
@os_run_priority,
@database_name OUTPUT,
@database_user_name OUTPUT,
@flags,
@output_file_name,
@new_proxy_id
IF (@retval <> 0)
RETURN(1) -- Failure
BEGIN TRANSACTION
-- Update the job's version/last-modified information
UPDATE msdb.dbo.sysjobs
SET version_number = version_number + 1,
date_modified = GETDATE()
WHERE (job_id = @job_id)
-- Update the step
UPDATE msdb.dbo.sysjobsteps
SET step_name = @step_name,
subsystem = @subsystem,
command = @command,
flags = @flags,
additional_parameters = @additional_parameters,
cmdexec_success_code = @cmdexec_success_code,
on_success_action = @on_success_action,
on_success_step_id = @on_success_step_id,
on_fail_action = @on_fail_action,
on_fail_step_id = @on_fail_step_id,
server = @server,
database_name = @database_name,
database_user_name = @database_user_name,
retry_attempts = @retry_attempts,
retry_interval = @retry_interval,
os_run_priority = @os_run_priority,
output_file_name = @output_file_name,
last_run_outcome = @x_last_run_outcome,
last_run_duration = @x_last_run_duration,
last_run_retries = @x_last_run_retries,
last_run_date = @x_last_run_date,
last_run_time = @x_last_run_time,
proxy_id = @new_proxy_id
WHERE (job_id = @job_id)
AND (step_id = @step_id)
COMMIT TRANSACTION
-- For a multi-server job, push changes to the target servers
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id <> 0)))
BEGIN
EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_DELETE_JOBSTEP */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_jobstep...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_jobstep')
AND (type = 'P')))
DROP PROCEDURE sp_delete_jobstep
go
CREATE PROCEDURE sp_delete_jobstep
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@step_id INT
AS
BEGIN
DECLARE @retval INT
DECLARE @max_step_id INT
DECLARE @valid_range VARCHAR(50)
DECLARE @job_owner_sid VARBINARY(85)
SET NOCOUNT ON
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check authority (only SQLServerAgent can delete a step of a non-local job)
EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = 'SQLAgent%'
IF (@retval <> 0)
RETURN(@retval)
-- SQLAgentReader and SQLAgentOperator roles that can see all jobs
-- cannot modify jobs they do not own
IF (@job_owner_sid <> SUSER_SID() -- does not own the job
AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)) -- is not sysadmin
BEGIN
RAISERROR(14525, -1, -1);
RETURN(1) -- Failure
END
-- Get current maximum step id
SELECT @max_step_id = ISNULL(MAX(step_id), 0)
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
-- Check step id
IF (@step_id < 0) OR (@step_id > @max_step_id)
BEGIN
SELECT @valid_range = FORMATMESSAGE(14201) + CONVERT(VARCHAR, @max_step_id)
RAISERROR(14266, -1, -1, '@step_id', @valid_range)
RETURN(1) -- Failure
END
BEGIN TRANSACTION
-- Delete either the specified step or ALL the steps (if step id is 0)
IF (@step_id = 0)
BEGIN
DELETE FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
END
ELSE
BEGIN
DELETE FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND (step_id = @step_id)
END
IF (@step_id <> 0)
BEGIN
-- Adjust step id's
UPDATE msdb.dbo.sysjobsteps
SET step_id = step_id - 1
WHERE (step_id > @step_id)
AND (job_id = @job_id)
-- Clean up OnSuccess/OnFail references
UPDATE msdb.dbo.sysjobsteps
SET on_success_step_id = on_success_step_id - 1
WHERE (on_success_step_id > @step_id)
AND (job_id = @job_id)
UPDATE msdb.dbo.sysjobsteps
SET on_fail_step_id = on_fail_step_id - 1
WHERE (on_fail_step_id > @step_id)
AND (job_id = @job_id)
UPDATE msdb.dbo.sysjobsteps
SET on_success_step_id = 0,
on_success_action = 1 -- Quit With Success
WHERE (on_success_step_id = @step_id)
AND (job_id = @job_id)
UPDATE msdb.dbo.sysjobsteps
SET on_fail_step_id = 0,
on_fail_action = 2 -- Quit With Failure
WHERE (on_fail_step_id = @step_id)
AND (job_id = @job_id)
END
-- Update the job's version/last-modified information
UPDATE msdb.dbo.sysjobs
SET version_number = version_number + 1,
date_modified = GETDATE()
WHERE (job_id = @job_id)
COMMIT TRANSACTION
-- Make sure that SQLServerAgent refreshes the job if the 'Has Steps' property has changed
IF ((SELECT COUNT(*)
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)) = 0)
BEGIN
-- NOTE: We only notify SQLServerAgent if we know the job has been cached
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)))
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',
@job_id = @job_id,
@action_type = N'U'
END
-- For a multi-server job, push changes to the target servers
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id <> 0)))
BEGIN
EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_HELP_JOBSTEP */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_jobstep...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_jobstep')
AND (type = 'P')))
DROP PROCEDURE sp_help_jobstep
go
CREATE PROCEDURE sp_help_jobstep
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@step_id INT = NULL,
@step_name sysname = NULL,
@suffix BIT = 0 -- A flag to control how the result set is formatted
AS
BEGIN
DECLARE @retval INT
DECLARE @max_step_id INT
DECLARE @valid_range VARCHAR(50)
SET NOCOUNT ON
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
'NO_TEST'
IF (@retval <> 0)
RETURN(1) -- Failure
-- The suffix flag must be either 0 (ie. no suffix) or 1 (ie. add suffix). 0 is the default.
IF (@suffix <> 0)
SELECT @suffix = 1
-- Check step id (if supplied)
IF (@step_id IS NOT NULL)
BEGIN
-- Get current maximum step id
SELECT @max_step_id = ISNULL(MAX(step_id), 0)
FROM msdb.dbo.sysjobsteps
WHERE job_id = @job_id
IF @max_step_id = 0
BEGIN
RAISERROR(14528, -1, -1, @job_name)
RETURN(1) -- Failure
END
ELSE IF (@step_id < 1) OR (@step_id > @max_step_id)
BEGIN
SELECT @valid_range = '1..' + CONVERT(VARCHAR, @max_step_id)
RAISERROR(14266, -1, -1, '@step_id', @valid_range)
RETURN(1) -- Failure
END
END
-- Check step name (if supplied)
-- NOTE: A supplied step id overrides a supplied step name
IF ((@step_id IS NULL) AND (@step_name IS NOT NULL))
BEGIN
SELECT @step_id = step_id
FROM msdb.dbo.sysjobsteps
WHERE (step_name = @step_name)
AND (job_id = @job_id)
IF (@step_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@step_name', @step_name)
RETURN(1) -- Failure
END
END
-- Return the job steps for this job (or just return the specific step)
IF (@suffix = 0)
BEGIN
SELECT step_id,
step_name,
subsystem,
command,
flags,
cmdexec_success_code,
on_success_action,
on_success_step_id,
on_fail_action,
on_fail_step_id,
server,
database_name,
database_user_name,
retry_attempts,
retry_interval,
os_run_priority,
output_file_name,
last_run_outcome,
last_run_duration,
last_run_retries,
last_run_date,
last_run_time,
proxy_id
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND ((@step_id IS NULL) OR (step_id = @step_id))
ORDER BY job_id, step_id
END
ELSE
BEGIN
SELECT step_id,
step_name,
subsystem,
command,
'flags' = CONVERT(NVARCHAR, flags) + N' (' +
ISNULL(CASE WHEN (flags = 0) THEN FORMATMESSAGE(14561) END, '') +
ISNULL(CASE WHEN (flags & 1) = 1 THEN FORMATMESSAGE(14558) + ISNULL(CASE WHEN (flags > 1) THEN N', ' END, '') END, '') +
ISNULL(CASE WHEN (flags & 2) = 2 THEN FORMATMESSAGE(14559) + ISNULL(CASE WHEN (flags > 3) THEN N', ' END, '') END, '') +
ISNULL(CASE WHEN (flags & 4) = 4 THEN FORMATMESSAGE(14560) END, '') + N')',
cmdexec_success_code,
'on_success_action' = CASE on_success_action
WHEN 1 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14562)
WHEN 2 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14563)
WHEN 3 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14564)
WHEN 4 THEN CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14565)
ELSE CONVERT(NVARCHAR, on_success_action) + N' ' + FORMATMESSAGE(14205)
END,
on_success_step_id,
'on_fail_action' = CASE on_fail_action
WHEN 1 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14562)
WHEN 2 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14563)
WHEN 3 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14564)
WHEN 4 THEN CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14565)
ELSE CONVERT(NVARCHAR, on_fail_action) + N' ' + FORMATMESSAGE(14205)
END,
on_fail_step_id,
server,
database_name,
database_user_name,
retry_attempts,
retry_interval,
'os_run_priority' = CASE os_run_priority
WHEN -15 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14566)
WHEN -1 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14567)
WHEN 0 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14561)
WHEN 1 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14568)
WHEN 15 THEN CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14569)
ELSE CONVERT(NVARCHAR, os_run_priority) + N' ' + FORMATMESSAGE(14205)
END,
output_file_name,
last_run_outcome,
last_run_duration,
last_run_retries,
last_run_date,
last_run_time,
proxy_id
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND ((@step_id IS NULL) OR (step_id = @step_id))
ORDER BY job_id, step_id
END
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_WRITE_SYSJOBSTEP_LOG */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_write_sysjobstep_log...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_write_sysjobstep_log')
AND (type = 'P')))
DROP PROCEDURE sp_write_sysjobstep_log
go
CREATE PROCEDURE sp_write_sysjobstep_log
@job_id UNIQUEIDENTIFIER,
@step_id INT,
@log_text NVARCHAR(MAX),
@append_to_last INT = 0
AS
BEGIN
DECLARE @step_uid UNIQUEIDENTIFIER
DECLARE @log_already_exists int
SET @log_already_exists = 0
SET @step_uid = ( SELECT step_uid FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND (step_id = @step_id) )
IF(EXISTS(SELECT * FROM msdb.dbo.sysjobstepslogs
WHERE step_uid = @step_uid ))
BEGIN
SET @log_already_exists = 1
END
--Need create log if "overwrite is selected or log does not exists.
IF (@append_to_last = 0) OR (@log_already_exists = 0)
BEGIN
-- flag is overwrite
--if overwrite and log exists, delete it
IF (@append_to_last = 0 AND @log_already_exists = 1)
BEGIN
-- remove previous logs entries
EXEC sp_delete_jobsteplog @job_id, NULL, @step_id, NULL
END
INSERT INTO msdb.dbo.sysjobstepslogs
(
log,
log_size,
step_uid
)
VALUES
(
@log_text,
DATALENGTH(@log_text),
@step_uid
)
END
ELSE
BEGIN
DECLARE @log_id INT
--Selecting TOP is just a safety net - there is only one log entry row per step.
SET @log_id = ( SELECT TOP 1 log_id FROM msdb.dbo.sysjobstepslogs
WHERE (step_uid = @step_uid)
ORDER BY log_id DESC )
-- Append @log_text to the existing log record. Note that if this
-- action would make the value of the log column longer than
-- nvarchar(max), then the engine will raise error 599.
UPDATE msdb.dbo.sysjobstepslogs
SET
log .WRITE(@log_text,NULL,0),
log_size = DATALENGTH(log) + DATALENGTH(@log_text) ,
date_modified = getdate()
WHERE log_id = @log_id
END
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_HELP_JOBSTEPLOG */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_jobsteplog...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_jobsteplog')
AND (type = 'P')))
DROP PROCEDURE sp_help_jobsteplog
go
CREATE PROCEDURE sp_help_jobsteplog
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@step_id INT = NULL,
@step_name sysname = NULL
AS
BEGIN
DECLARE @retval INT
DECLARE @max_step_id INT
DECLARE @valid_range VARCHAR(50)
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
'NO_TEST'
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check step id (if supplied)
IF (@step_id IS NOT NULL)
BEGIN
-- Get current maximum step id
SELECT @max_step_id = ISNULL(MAX(step_id), 0)
FROM msdb.dbo.sysjobsteps
WHERE job_id = @job_id
IF @max_step_id = 0
BEGIN
RAISERROR(14528, -1, -1, @job_name)
RETURN(1) -- Failure
END
ELSE IF (@step_id < 1) OR (@step_id > @max_step_id)
BEGIN
SELECT @valid_range = '1..' + CONVERT(VARCHAR, @max_step_id)
RAISERROR(14266, -1, -1, '@step_id', @valid_range)
RETURN(1) -- Failure
END
END
-- Check step name (if supplied)
-- NOTE: A supplied step id overrides a supplied step name
IF ((@step_id IS NULL) AND (@step_name IS NOT NULL))
BEGIN
SELECT @step_id = step_id
FROM msdb.dbo.sysjobsteps
WHERE (step_name = @step_name)
AND (job_id = @job_id)
IF (@step_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@step_name', @step_name)
RETURN(1) -- Failure
END
END
SELECT sjv.job_id,
@job_name as job_name,
steps.step_id,
steps.step_name,
steps.step_uid,
logs.date_created,
logs.date_modified,
logs.log_size,
logs.log
FROM msdb.dbo.sysjobs_view sjv, msdb.dbo.sysjobsteps as steps, msdb.dbo.sysjobstepslogs as logs
WHERE (sjv.job_id = @job_id)
AND (steps.job_id = @job_id)
AND ((@step_id IS NULL) OR (step_id = @step_id))
AND (steps.step_uid = logs.step_uid)
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_DELETE_JOBSTEPLOG */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_jobsteplog...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_jobsteplog')
AND (type = 'P')))
DROP PROCEDURE sp_delete_jobsteplog
go
CREATE PROCEDURE sp_delete_jobsteplog
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@step_id INT = NULL,
@step_name sysname = NULL,
@older_than datetime = NULL,
@larger_than int = NULL -- (in megabytes)
AS
BEGIN
DECLARE @retval INT
DECLARE @max_step_id INT
DECLARE @valid_range VARCHAR(50)
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
'NO_TEST'
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check step id (if supplied)
IF (@step_id IS NOT NULL)
BEGIN
-- Get current maximum step id
SELECT @max_step_id = ISNULL(MAX(step_id), 0)
FROM msdb.dbo.sysjobsteps
WHERE job_id = @job_id
IF @max_step_id = 0
BEGIN
RAISERROR(14528, -1, -1, @job_name)
RETURN(1) -- Failure
END
ELSE IF (@step_id < 1) OR (@step_id > @max_step_id)
BEGIN
SELECT @valid_range = '1..' + CONVERT(VARCHAR, @max_step_id)
RAISERROR(14266, -1, -1, '@step_id', @valid_range)
RETURN(1) -- Failure
END
END
-- Check step name (if supplied)
-- NOTE: A supplied step id overrides a supplied step name
IF ((@step_id IS NULL) AND (@step_name IS NOT NULL))
BEGIN
SELECT @step_id = step_id
FROM msdb.dbo.sysjobsteps
WHERE (step_name = @step_name)
AND (job_id = @job_id)
IF (@step_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@step_name', @step_name)
RETURN(1) -- Failure
END
END
-- Delete either the specified step or ALL the steps (if step id is NULL)
DELETE FROM msdb.dbo.sysjobstepslogs
WHERE (step_uid IN (SELECT DISTINCT step_uid
FROM msdb.dbo.sysjobsteps js, msdb.dbo.sysjobs_view jv
WHERE ( @job_id = jv.job_id )
AND (js.job_id = jv.job_id )
AND ((@step_id IS NULL) OR (@step_id = step_id))))
AND ((@older_than IS NULL) OR (date_modified < @older_than))
AND ((@larger_than IS NULL) OR (log_size > @larger_than))
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_GET_SCHEDULE_DESCRIPTION */
/* */
/* NOTE: This SP only returns an English description of the */
/* schedule due to the piecemeal nature of the */
/* description's construction. */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_get_schedule_description...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_get_schedule_description')
AND (type = 'P')))
DROP PROCEDURE sp_get_schedule_description
go
CREATE PROCEDURE sp_get_schedule_description
@freq_type INT = NULL,
@freq_interval INT = NULL,
@freq_subday_type INT = NULL,
@freq_subday_interval INT = NULL,
@freq_relative_interval INT = NULL,
@freq_recurrence_factor INT = NULL,
@active_start_date INT = NULL,
@active_end_date INT = NULL,
@active_start_time INT = NULL,
@active_end_time INT = NULL,
@schedule_description NVARCHAR(255) OUTPUT
AS
BEGIN
DECLARE @loop INT
DECLARE @idle_cpu_percent INT
DECLARE @idle_cpu_duration INT
SET NOCOUNT ON
IF (@freq_type = 0x1) -- OneTime
BEGIN
SELECT @schedule_description = N'Once on ' + CONVERT(NVARCHAR, @active_start_date) + N' at ' + CONVERT(NVARCHAR, @active_start_time)
RETURN
END
IF (@freq_type = 0x4) -- Daily
BEGIN
SELECT @schedule_description = N'Every day '
END
IF (@freq_type = 0x8) -- Weekly
BEGIN
SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' week(s) on '
SELECT @loop = 1
WHILE (@loop <= 7)
BEGIN
IF (@freq_interval & POWER(2, @loop - 1) = POWER(2, @loop - 1))
SELECT @schedule_description = @schedule_description + DATENAME(dw, N'1996120' + CONVERT(NVARCHAR, @loop)) + N', '
SELECT @loop = @loop + 1
END
IF (RIGHT(@schedule_description, 2) = N', ')
SELECT @schedule_description = SUBSTRING(@schedule_description, 1, (DATALENGTH(@schedule_description) / 2) - 2) + N' '
END
IF (@freq_type = 0x10) -- Monthly
BEGIN
SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' months(s) on day ' + CONVERT(NVARCHAR, @freq_interval) + N' of that month '
END
IF (@freq_type = 0x20) -- Monthly Relative
BEGIN
SELECT @schedule_description = N'Every ' + CONVERT(NVARCHAR, @freq_recurrence_factor) + N' months(s) on the '
SELECT @schedule_description = @schedule_description +
CASE @freq_relative_interval
WHEN 0x01 THEN N'first '
WHEN 0x02 THEN N'second '
WHEN 0x04 THEN N'third '
WHEN 0x08 THEN N'fourth '
WHEN 0x10 THEN N'last '
END +
CASE
WHEN (@freq_interval > 00)
AND (@freq_interval < 08) THEN DATENAME(dw, N'1996120' + CONVERT(NVARCHAR, @freq_interval))
WHEN (@freq_interval = 08) THEN N'day'
WHEN (@freq_interval = 09) THEN N'week day'
WHEN (@freq_interval = 10) THEN N'weekend day'
END + N' of that month '
END
IF (@freq_type = 0x40) -- AutoStart
BEGIN
SELECT @schedule_description = FORMATMESSAGE(14579)
RETURN
END
IF (@freq_type = 0x80) -- OnIdle
BEGIN
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'IdleCPUPercent',
@idle_cpu_percent OUTPUT,
N'no_output'
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'IdleCPUDuration',
@idle_cpu_duration OUTPUT,
N'no_output'
SELECT @schedule_description = FORMATMESSAGE(14578, ISNULL(@idle_cpu_percent, 10), ISNULL(@idle_cpu_duration, 600))
RETURN
END
-- Subday stuff
SELECT @schedule_description = @schedule_description +
CASE @freq_subday_type
WHEN 0x1 THEN N'at ' + CONVERT(NVARCHAR, @active_start_time)
WHEN 0x2 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' second(s)'
WHEN 0x4 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' minute(s)'
WHEN 0x8 THEN N'every ' + CONVERT(NVARCHAR, @freq_subday_interval) + N' hour(s)'
END
IF (@freq_subday_type IN (0x2, 0x4, 0x8))
SELECT @schedule_description = @schedule_description + N' between ' +
CONVERT(NVARCHAR, @active_start_time) + N' and ' + CONVERT(NVARCHAR, @active_end_time)
END
go
CHECKPOINT
go
/**************************************************************/
/* SP_ADD_JOBSCHEDULE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_jobschedule...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_jobschedule')
AND (type = 'P')))
DROP PROCEDURE sp_add_jobschedule
go
CREATE PROCEDURE sp_add_jobschedule -- This SP is deprecated. Use sp_add_schedule and sp_attach_schedule.
@job_id UNIQUEIDENTIFIER = NULL,
@job_name sysname = NULL,
@name sysname,
@enabled TINYINT = 1,
@freq_type INT = 1,
@freq_interval INT = 0,
@freq_subday_type INT = 0,
@freq_subday_interval INT = 0,
@freq_relative_interval INT = 0,
@freq_recurrence_factor INT = 0,
@active_start_date INT = NULL, -- sp_verify_schedule assigns a default
@active_end_date INT = 99991231, -- December 31st 9999
@active_start_time INT = 000000, -- 12:00:00 am
@active_end_time INT = 235959, -- 11:59:59 pm
@schedule_id INT = NULL OUTPUT,
@automatic_post BIT = 1, -- If 1 will post notifications to all tsx servers to that run this job
@schedule_uid UNIQUEIDENTIFIER = NULL OUTPUT
AS
BEGIN
DECLARE @retval INT
DECLARE @owner_login_name sysname
SET NOCOUNT ON
-- Check authority (only SQLServerAgent can add a schedule to a non-local job)
EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
IF (@retval <> 0)
RETURN(@retval)
-- Check that we can uniquely identify the job
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Get the owner of the job. Prior to resusable schedules the job owner also owned the schedule
SELECT @owner_login_name = dbo.SQLAGENT_SUSER_SNAME(owner_sid)
FROM sysjobs
WHERE (job_id = @job_id)
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1) AND
(SUSER_SNAME() <> @owner_login_name))
BEGIN
RAISERROR(14525, -1, -1)
RETURN(1) -- Failure
END
-- Check authority (only SQLServerAgent can add a schedule to a non-local job)
EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
IF (@retval <> 0)
RETURN(@retval)
-- Add the schedule first
EXECUTE @retval = msdb.dbo.sp_add_schedule @schedule_name = @name,
@enabled = @enabled,
@freq_type = @freq_type,
@freq_interval = @freq_interval,
@freq_subday_type = @freq_subday_type,
@freq_subday_interval = @freq_subday_interval,
@freq_relative_interval = @freq_relative_interval,
@freq_recurrence_factor = @freq_recurrence_factor,
@active_start_date = @active_start_date,
@active_end_date = @active_end_date,
@active_start_time = @active_start_time,
@active_end_time = @active_end_time,
@owner_login_name = @owner_login_name,
@schedule_uid = @schedule_uid OUTPUT,
@schedule_id = @schedule_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
EXECUTE @retval = msdb.dbo.sp_attach_schedule @job_id = @job_id,
@job_name = NULL,
@schedule_id = @schedule_id,
@schedule_name = NULL,
@automatic_post = @automatic_post
IF (@retval <> 0)
RETURN(1) -- Failure
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_UPDATE_JOBSCHEDULE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_jobschedule...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_update_jobschedule')
AND (type = 'P')))
DROP PROCEDURE sp_update_jobschedule
go
CREATE PROCEDURE sp_update_jobschedule -- This SP is deprecated by sp_update_schedule.
@job_id UNIQUEIDENTIFIER = NULL,
@job_name sysname = NULL,
@name sysname,
@new_name sysname = NULL,
@enabled TINYINT = NULL,
@freq_type INT = NULL,
@freq_interval INT = NULL,
@freq_subday_type INT = NULL,
@freq_subday_interval INT = NULL,
@freq_relative_interval INT = NULL,
@freq_recurrence_factor INT = NULL,
@active_start_date INT = NULL,
@active_end_date INT = NULL,
@active_start_time INT = NULL,
@active_end_time INT = NULL,
@automatic_post BIT = 1 -- If 1 will post notifications to all tsx servers to that run this job
AS
BEGIN
DECLARE @retval INT
DECLARE @sched_count INT
DECLARE @schedule_id INT
DECLARE @job_owner_sid VARBINARY(85)
DECLARE @enable_only_used INT
DECLARE @x_name sysname
DECLARE @x_enabled TINYINT
DECLARE @x_freq_type INT
DECLARE @x_freq_interval INT
DECLARE @x_freq_subday_type INT
DECLARE @x_freq_subday_interval INT
DECLARE @x_freq_relative_interval INT
DECLARE @x_freq_recurrence_factor INT
DECLARE @x_active_start_date INT
DECLARE @x_active_end_date INT
DECLARE @x_active_start_time INT
DECLARE @x_active_end_time INT
DECLARE @owner_sid VARBINARY(85)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
SELECT @new_name = LTRIM(RTRIM(@new_name))
-- Turn [nullable] empty string parameters into NULLs
IF (@new_name = N'') SELECT @new_name = NULL
-- Check authority (only SQLServerAgent can modify a schedule of a non-local job)
EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = 'SQLAgent%'
IF (@retval <> 0)
RETURN(@retval)
-- Check that we can uniquely identify the job
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Is @enable the only parameter used beside jobname and jobid?
IF ((@enabled IS NOT NULL) AND
(@name IS NULL) AND
(@new_name IS NULL) AND
(@freq_type IS NULL) AND
(@freq_interval IS NULL) AND
(@freq_subday_type IS NULL) AND
(@freq_subday_interval IS NULL) AND
(@freq_relative_interval IS NULL) AND
(@freq_recurrence_factor IS NULL) AND
(@active_start_date IS NULL) AND
(@active_end_date IS NULL) AND
(@active_start_time IS NULL) AND
(@active_end_time IS NULL))
SELECT @enable_only_used = 1
ELSE
SELECT @enable_only_used = 0
IF ((SUSER_SID() <> @job_owner_sid)
AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
AND (@enable_only_used <> 1 OR ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) <> 1))
BEGIN
RAISERROR(14525, -1, -1)
RETURN(1) -- Failure
END
-- Make sure the schedule_id can be uniquely identified and that it exists
-- Note: It's safe use the values returned by the MIN() function because the SP errors out if more than 1 record exists
SELECT @sched_count = COUNT(*),
@schedule_id = MIN(sched.schedule_id),
@owner_sid = MIN(sched.owner_sid)
FROM msdb.dbo.sysjobschedules as jsched
JOIN msdb.dbo.sysschedules_localserver_view as sched
ON jsched.schedule_id = sched.schedule_id
WHERE (jsched.job_id = @job_id)
AND (sched.name = @name)
-- Need to use sp_update_schedule to update this ambiguous schedule name
IF(@sched_count > 1)
BEGIN
RAISERROR(14375, -1, -1, @name, @job_name)
RETURN(1) -- Failure
END
IF (@schedule_id IS NULL)
BEGIN
--raise an explicit message if the schedule does exist but isn't attached to this job
IF EXISTS(SELECT *
FROM sysschedules_localserver_view
WHERE (name = @name))
BEGIN
RAISERROR(14374, -1, -1, @name, @job_name)
END
ELSE
BEGIN
--If the schedule is from an MSX and a sysadmin is calling report a specific 'MSX' message
IF(PROGRAM_NAME() NOT LIKE N'SQLAgent%' AND
ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1 AND
EXISTS(SELECT *
FROM msdb.dbo.sysschedules as sched
JOIN msdb.dbo.sysoriginatingservers_view as svr
ON sched.originating_server_id = svr.originating_server_id
JOIN msdb.dbo.sysjobschedules as js
ON sched.schedule_id = js.schedule_id
WHERE (svr.master_server = 1) AND
(sched.name = @name) AND
(js.job_id = @job_id)))
BEGIN
RAISERROR(14274, -1, -1)
END
ELSE
BEGIN
--Generic message that the schedule doesn't exist
RAISERROR(14262, -1, -1, 'Schedule Name', @name)
END
END
RETURN(1) -- Failure
END
-- Set the x_ (existing) variables
SELECT @x_name = name,
@x_enabled = enabled,
@x_freq_type = freq_type,
@x_freq_interval = freq_interval,
@x_freq_subday_type = freq_subday_type,
@x_freq_subday_interval = freq_subday_interval,
@x_freq_relative_interval = freq_relative_interval,
@x_freq_recurrence_factor = freq_recurrence_factor,
@x_active_start_date = active_start_date,
@x_active_end_date = active_end_date,
@x_active_start_time = active_start_time,
@x_active_end_time = active_end_time
FROM msdb.dbo.sysschedules_localserver_view
WHERE (schedule_id = @schedule_id )
-- Fill out the values for all non-supplied parameters from the existing values
IF (@new_name IS NULL) SELECT @new_name = @x_name
IF (@enabled IS NULL) SELECT @enabled = @x_enabled
IF (@freq_type IS NULL) SELECT @freq_type = @x_freq_type
IF (@freq_interval IS NULL) SELECT @freq_interval = @x_freq_interval
IF (@freq_subday_type IS NULL) SELECT @freq_subday_type = @x_freq_subday_type
IF (@freq_subday_interval IS NULL) SELECT @freq_subday_interval = @x_freq_subday_interval
IF (@freq_relative_interval IS NULL) SELECT @freq_relative_interval = @x_freq_relative_interval
IF (@freq_recurrence_factor IS NULL) SELECT @freq_recurrence_factor = @x_freq_recurrence_factor
IF (@active_start_date IS NULL) SELECT @active_start_date = @x_active_start_date
IF (@active_end_date IS NULL) SELECT @active_end_date = @x_active_end_date
IF (@active_start_time IS NULL) SELECT @active_start_time = @x_active_start_time
IF (@active_end_time IS NULL) SELECT @active_end_time = @x_active_end_time
-- Check schedule (frequency and owner) parameters
EXECUTE @retval = sp_verify_schedule @schedule_id = @schedule_id,
@name = @new_name,
@enabled = @enabled,
@freq_type = @freq_type,
@freq_interval = @freq_interval OUTPUT,
@freq_subday_type = @freq_subday_type OUTPUT,
@freq_subday_interval = @freq_subday_interval OUTPUT,
@freq_relative_interval = @freq_relative_interval OUTPUT,
@freq_recurrence_factor = @freq_recurrence_factor OUTPUT,
@active_start_date = @active_start_date OUTPUT,
@active_start_time = @active_start_time OUTPUT,
@active_end_date = @active_end_date OUTPUT,
@active_end_time = @active_end_time OUTPUT,
@owner_sid = @owner_sid
IF (@retval <> 0)
RETURN(1) -- Failure
-- Update the JobSchedule
UPDATE msdb.dbo.sysschedules
SET name = @new_name,
enabled = @enabled,
freq_type = @freq_type,
freq_interval = @freq_interval,
freq_subday_type = @freq_subday_type,
freq_subday_interval = @freq_subday_interval,
freq_relative_interval = @freq_relative_interval,
freq_recurrence_factor = @freq_recurrence_factor,
active_start_date = @active_start_date,
active_end_date = @active_end_date,
active_start_time = @active_start_time,
active_end_time = @active_end_time,
date_modified = GETDATE(),
version_number = version_number + 1
WHERE (schedule_id = @schedule_id)
SELECT @retval = @@error
-- Update the job's version/last-modified information
UPDATE msdb.dbo.sysjobs
SET version_number = version_number + 1,
date_modified = GETDATE()
WHERE (job_id = @job_id)
-- Notify SQLServerAgent of the change, but only if we know the job has been cached
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)))
BEGIN
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'S',
@job_id = @job_id,
@schedule_id = @schedule_id,
@action_type = N'U'
END
-- For a multi-server job, remind the user that they need to call sp_post_msx_operation
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id <> 0)))
-- Instruct the tsx servers to pick up the altered schedule
IF (@automatic_post = 1)
BEGIN
DECLARE @schedule_uid UNIQUEIDENTIFIER
SELECT @schedule_uid = schedule_uid
FROM sysschedules
WHERE schedule_id = @schedule_id
IF(NOT @schedule_uid IS NULL)
BEGIN
-- sp_post_msx_operation will do nothing if the schedule isn't assigned to any tsx machines
EXECUTE sp_post_msx_operation @operation = 'INSERT', @object_type = 'SCHEDULE', @schedule_uid = @schedule_uid
END
END
ELSE
RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
-- Automatic addition and removal of -Continous parameter for replication agent
EXECUTE sp_update_replication_job_parameter @job_id = @job_id,
@old_freq_type = @x_freq_type,
@new_freq_type = @freq_type
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_DELETE_JOBSCHEDULE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_jobschedule...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_delete_jobschedule')
AND (type = 'P')))
DROP PROCEDURE sp_delete_jobschedule
go
CREATE PROCEDURE sp_delete_jobschedule -- This SP is deprecated. Use sp_detach_schedule and sp_delete_schedule.
@job_id UNIQUEIDENTIFIER = NULL,
@job_name sysname = NULL,
@name sysname,
@keep_schedule int = 0,
@automatic_post BIT = 1 -- If 1 will post notifications to all tsx servers to that run this schedule
AS
BEGIN
DECLARE @retval INT
DECLARE @sched_count INT
DECLARE @schedule_id INT
DECLARE @job_owner_sid VARBINARY(85)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
-- Check authority (only SQLServerAgent can delete a schedule of a non-local job)
EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
IF (@retval <> 0)
RETURN(@retval)
-- Check that we can uniquely identify the job
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1) AND
(SUSER_SID() <> @job_owner_sid))
BEGIN
RAISERROR(14525, -1, -1)
RETURN(1) -- Failure
END
IF (UPPER(@name collate SQL_Latin1_General_CP1_CS_AS) = N'ALL')
BEGIN
SELECT @schedule_id = -1 -- We use this in the call to sp_sqlagent_notify
--Delete the schedule(s) if it isn't being used by other jobs
DECLARE @temp_schedules_to_delete TABLE (schedule_id INT NOT NULL)
--If user requests that the schedules be removed (the legacy behavoir)
--make sure it isnt being used by other jobs
IF (@keep_schedule = 0)
BEGIN
--Get the list of schedules to delete
INSERT INTO @temp_schedules_to_delete
SELECT DISTINCT schedule_id
FROM msdb.dbo.sysschedules
WHERE (schedule_id IN
(SELECT schedule_id
FROM msdb.dbo.sysjobschedules
WHERE (job_id = @job_id)))
--make sure no other jobs use these schedules
IF( EXISTS(SELECT *
FROM msdb.dbo.sysjobschedules
WHERE (job_id <> @job_id)
AND (schedule_id in ( SELECT schedule_id
FROM @temp_schedules_to_delete ))))
BEGIN
RAISERROR(14367, -1, -1)
RETURN(1) -- Failure
END
END
--OK to delete the jobschedule
DELETE FROM msdb.dbo.sysjobschedules
WHERE (job_id = @job_id)
--OK to delete the schedule - temp_schedules_to_delete is empty if @keep_schedule <> 0
DELETE FROM msdb.dbo.sysschedules
WHERE schedule_id IN
(SELECT schedule_id from @temp_schedules_to_delete)
END
ELSE
BEGIN
-- Make sure the schedule_id can be uniquely identified and that it exists
-- Note: It's safe use the values returned by the MIN() function because the SP errors out if more than 1 record exists
SELECT @sched_count = COUNT(*),
@schedule_id = MIN(sched.schedule_id)
FROM msdb.dbo.sysjobschedules as jsched
JOIN msdb.dbo.sysschedules_localserver_view as sched
ON jsched.schedule_id = sched.schedule_id
WHERE (jsched.job_id = @job_id)
AND (sched.name = @name)
-- Need to use sp_detach_schedule to remove this ambiguous schedule name
IF(@sched_count > 1)
BEGIN
RAISERROR(14376, -1, -1, @name, @job_name)
RETURN(1) -- Failure
END
IF (@schedule_id IS NULL)
BEGIN
--raise an explicit message if the schedule does exist but isn't attached to this job
IF EXISTS(SELECT *
FROM sysschedules_localserver_view
WHERE (name = @name))
BEGIN
RAISERROR(14374, -1, -1, @name, @job_name)
END
ELSE
BEGIN
--If the schedule is from an MSX and a sysadmin is calling report a specific 'MSX' message
IF(PROGRAM_NAME() NOT LIKE N'SQLAgent%' AND
ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1 AND
EXISTS(SELECT *
FROM msdb.dbo.sysschedules as sched
JOIN msdb.dbo.sysoriginatingservers_view as svr
ON sched.originating_server_id = svr.originating_server_id
JOIN msdb.dbo.sysjobschedules as js
ON sched.schedule_id = js.schedule_id
WHERE (svr.master_server = 1) AND
(sched.name = @name) AND
(js.job_id = @job_id)))
BEGIN
RAISERROR(14274, -1, -1)
END
ELSE
BEGIN
--Generic message that the schedule doesn't exist
RAISERROR(14262, -1, -1, '@name', @name)
END
END
RETURN(1) -- Failure
END
--If user requests that the schedule be removed (the legacy behavoir)
--make sure it isnt being used by another job
IF (@keep_schedule = 0)
BEGIN
IF( EXISTS(SELECT *
FROM msdb.dbo.sysjobschedules
WHERE (schedule_id = @schedule_id)
AND (job_id <> @job_id) ))
BEGIN
RAISERROR(14368, -1, -1, @name)
RETURN(1) -- Failure
END
END
--Delete the job schedule link first
DELETE FROM msdb.dbo.sysjobschedules
WHERE (job_id = @job_id)
AND (schedule_id = @schedule_id)
--Delete schedule if required
IF (@keep_schedule = 0)
BEGIN
--Now delete the schedule if required
DELETE FROM msdb.dbo.sysschedules
WHERE (schedule_id = @schedule_id)
END
END
-- Update the job's version/last-modified information
UPDATE msdb.dbo.sysjobs
SET version_number = version_number + 1,
date_modified = GETDATE()
WHERE (job_id = @job_id)
-- Notify SQLServerAgent of the change, but only if we know the job has been cached
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)))
BEGIN
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'S',
@job_id = @job_id,
@schedule_id = @schedule_id,
@action_type = N'D'
END
-- For a multi-server job, remind the user that they need to call sp_post_msx_operation
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id <> 0)))
-- Instruct the tsx servers to pick up the altered schedule
IF (@automatic_post = 1)
BEGIN
DECLARE @schedule_uid UNIQUEIDENTIFIER
SELECT @schedule_uid = schedule_uid
FROM sysschedules
WHERE schedule_id = @schedule_id
IF(NOT @schedule_uid IS NULL)
BEGIN
-- sp_post_msx_operation will do nothing if the schedule isn't assigned to any tsx machines
EXECUTE sp_post_msx_operation @operation = 'INSERT', @object_type = 'SCHEDULE', @schedule_uid = @schedule_uid
END
END
ELSE
RAISERROR(14547, 0, 1, N'INSERT', N'sp_post_msx_operation')
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_HELP_SCHEDULE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_schedule...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_schedule')
AND (type = 'P')))
DROP PROCEDURE sp_help_schedule
go
CREATE PROCEDURE sp_help_schedule
@schedule_id INT = NULL, -- If both @schedule_id and @schedule_name are NULL retreive all schedules
@schedule_name sysname = NULL,
@attached_schedules_only BIT = 0, -- If 1 only retreive all schedules that are attached to jobs
@include_description BIT = 0 -- 1 if a schedule description is required (NOTE: It's expensive to generate the description)
AS
BEGIN
DECLARE @retval INT
DECLARE @schedule_description NVARCHAR(255)
DECLARE @name sysname
DECLARE @freq_type INT
DECLARE @freq_interval INT
DECLARE @freq_subday_type INT
DECLARE @freq_subday_interval INT
DECLARE @freq_relative_interval INT
DECLARE @freq_recurrence_factor INT
DECLARE @active_start_date INT
DECLARE @active_end_date INT
DECLARE @active_start_time INT
DECLARE @active_end_time INT
DECLARE @schedule_id_as_char VARCHAR(10)
SET NOCOUNT ON
-- If both @schedule_id and @schedule_name are NULL retreive all schedules (depending on @attached_schedules_only)
-- otherwise verify the schedule exists
IF (@schedule_id IS NOT NULL) OR (@schedule_name IS NOT NULL)
BEGIN
-- Check that we can uniquely identify the schedule
EXECUTE @retval = msdb.dbo.sp_verify_schedule_identifiers @name_of_name_parameter = '@schedule_name',
@name_of_id_parameter = '@schedule_id',
@schedule_name = @schedule_name OUTPUT,
@schedule_id = @schedule_id OUTPUT,
@owner_sid = NULL,
@orig_server_id = NULL
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Get the schedule(s) that are attached to a job (or all schs if @attached_schedules_only = 0) into a temporary table
SELECT schedule_id,
schedule_uid,
'schedule_name' = name,
enabled,
freq_type,
freq_interval,
freq_subday_type,
freq_subday_interval,
freq_relative_interval,
freq_recurrence_factor,
active_start_date,
active_end_date,
active_start_time,
active_end_time,
date_created,
'schedule_description' = FORMATMESSAGE(14549)
INTO #temp_jobschedule
FROM msdb.dbo.sysschedules_localserver_view as sch
WHERE ( (@attached_schedules_only = 0)
OR (EXISTS(SELECT * FROM sysjobschedules as jobsch WHERE sch.schedule_id = jobsch.schedule_id)) )
AND((@schedule_id IS NULL) OR (schedule_id = @schedule_id))
IF (@include_description = 1)
BEGIN
-- For each schedule, generate the textual schedule description and update the temporary
-- table with it
IF (EXISTS (SELECT *
FROM #temp_jobschedule))
BEGIN
WHILE (EXISTS (SELECT *
FROM #temp_jobschedule
WHERE schedule_description = FORMATMESSAGE(14549)))
BEGIN
SET ROWCOUNT 1
SELECT @name = schedule_name,
@freq_type = freq_type,
@freq_interval = freq_interval,
@freq_subday_type = freq_subday_type,
@freq_subday_interval = freq_subday_interval,
@freq_relative_interval = freq_relative_interval,
@freq_recurrence_factor = freq_recurrence_factor,
@active_start_date = active_start_date,
@active_end_date = active_end_date,
@active_start_time = active_start_time,
@active_end_time = active_end_time
FROM #temp_jobschedule
WHERE (schedule_description = FORMATMESSAGE(14549))
SET ROWCOUNT 0
EXECUTE sp_get_schedule_description
@freq_type,
@freq_interval,
@freq_subday_type,
@freq_subday_interval,
@freq_relative_interval,
@freq_recurrence_factor,
@active_start_date,
@active_end_date,
@active_start_time,
@active_end_time,
@schedule_description OUTPUT
UPDATE #temp_jobschedule
SET schedule_description = ISNULL(LTRIM(RTRIM(@schedule_description)), FORMATMESSAGE(14205))
WHERE (schedule_name = @name)
END -- While
END
END
-- Return the result set, adding job count
SELECT *, (SELECT COUNT(*) FROM sysjobschedules WHERE sysjobschedules.schedule_id = #temp_jobschedule.schedule_id) as 'job_count'
FROM #temp_jobschedule
ORDER BY schedule_id
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_HELP_JOBSCHEDULE */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_jobschedule...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_jobschedule')
AND (type = 'P')))
DROP PROCEDURE sp_help_jobschedule
go
CREATE PROCEDURE sp_help_jobschedule
@job_id UNIQUEIDENTIFIER = NULL,
@job_name sysname = NULL,
@schedule_name sysname = NULL,
@schedule_id INT = NULL,
@include_description BIT = 0 -- 1 if a schedule description is required (NOTE: It's expensive to generate the description)
AS
BEGIN
DECLARE @retval INT
DECLARE @schedule_description NVARCHAR(255)
DECLARE @name sysname
DECLARE @freq_type INT
DECLARE @freq_interval INT
DECLARE @freq_subday_type INT
DECLARE @freq_subday_interval INT
DECLARE @freq_relative_interval INT
DECLARE @freq_recurrence_factor INT
DECLARE @active_start_date INT
DECLARE @active_end_date INT
DECLARE @active_start_time INT
DECLARE @active_end_time INT
DECLARE @schedule_id_as_char VARCHAR(10)
DECLARE @job_count INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @schedule_name = LTRIM(RTRIM(@schedule_name))
SELECT @job_count = 0
-- Turn [nullable] empty string parameters into NULLs
IF (@schedule_name = N'') SELECT @schedule_name = NULL
-- The user must provide either:
-- 1) job_id (or job_name) and (optionally) a schedule name
-- or...
-- 2) just schedule_id
IF (@schedule_id IS NULL) AND
(@job_id IS NULL) AND
(@job_name IS NULL)
BEGIN
RAISERROR(14273, -1, -1)
RETURN(1) -- Failure
END
IF (@schedule_id IS NOT NULL) AND ((@job_id IS NOT NULL) OR
(@job_name IS NOT NULL) OR
(@schedule_name IS NOT NULL))
BEGIN
RAISERROR(14273, -1, -1)
RETURN(1) -- Failure
END
-- Check that the schedule (by ID) exists and it is only used by one job.
-- Allowing this for backward compatibility with versions prior to V9
IF (@schedule_id IS NOT NULL) AND
(@job_id IS NULL) AND
(@job_name IS NULL)
BEGIN
SELECT @job_count = COUNT(*)
FROM msdb.dbo.sysjobschedules
WHERE (schedule_id = @schedule_id)
if(@job_count > 1)
BEGIN
SELECT @schedule_id_as_char = CONVERT(VARCHAR, @schedule_id)
RAISERROR(14369, -1, -1, @schedule_id_as_char)
RETURN(1) -- Failure
END
SELECT @job_id = job_id
FROM msdb.dbo.sysjobschedules
WHERE (schedule_id = @schedule_id)
IF (@job_id IS NULL)
BEGIN
SELECT @schedule_id_as_char = CONVERT(VARCHAR, @schedule_id)
RAISERROR(14262, -1, -1, '@schedule_id', @schedule_id_as_char)
RETURN(1) -- Failure
END
END
-- Check that we can uniquely identify the job
IF (@job_id IS NOT NULL) OR (@job_name IS NOT NULL)
BEGIN
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
'NO_TEST'
IF (@retval <> 0)
RETURN(1) -- Failure
END
IF (@schedule_id IS NOT NULL OR @schedule_name IS NOT NULL)
BEGIN
-- Check that we can uniquely identify the schedule
EXECUTE @retval = msdb.dbo.sp_verify_schedule_identifiers @name_of_name_parameter = '@schedule_name',
@name_of_id_parameter = '@schedule_id',
@schedule_name = @schedule_name OUTPUT,
@schedule_id = @schedule_id OUTPUT,
@owner_sid = NULL,
@orig_server_id = NULL,
@job_id_filter = @job_id
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Check that the schedule (by name) exists
IF (@schedule_name IS NOT NULL)
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobschedules AS js
JOIN msdb.dbo.sysschedules AS s
ON js.schedule_id = s.schedule_id
WHERE (js.job_id = @job_id)
AND (s.name = @schedule_name)))
BEGIN
RAISERROR(14262, -1, -1, '@schedule_name', @schedule_name)
RETURN(1) -- Failure
END
END
-- Get the schedule(s) into a temporary table
SELECT s.schedule_id,
'schedule_name' = name,
enabled,
freq_type,
freq_interval,
freq_subday_type,
freq_subday_interval,
freq_relative_interval,
freq_recurrence_factor,
active_start_date,
active_end_date,
active_start_time,
active_end_time,
date_created,
'schedule_description' = FORMATMESSAGE(14549),
js.next_run_date,
js.next_run_time,
s.schedule_uid
INTO #temp_jobschedule
FROM msdb.dbo.sysjobschedules AS js
JOIN msdb.dbo.sysschedules AS s
ON js.schedule_id = s.schedule_id
WHERE ((@job_id IS NULL) OR (js.job_id = @job_id))
AND ((@schedule_name IS NULL) OR (s.name = @schedule_name))
AND ((@schedule_id IS NULL) OR (s.schedule_id = @schedule_id))
IF (@include_description = 1)
BEGIN
-- For each schedule, generate the textual schedule description and update the temporary
-- table with it
IF (EXISTS (SELECT *
FROM #temp_jobschedule))
BEGIN
WHILE (EXISTS (SELECT *
FROM #temp_jobschedule
WHERE schedule_description = FORMATMESSAGE(14549)))
BEGIN
SET ROWCOUNT 1
SELECT @name = schedule_name,
@freq_type = freq_type,
@freq_interval = freq_interval,
@freq_subday_type = freq_subday_type,
@freq_subday_interval = freq_subday_interval,
@freq_relative_interval = freq_relative_interval,
@freq_recurrence_factor = freq_recurrence_factor,
@active_start_date = active_start_date,
@active_end_date = active_end_date,
@active_start_time = active_start_time,
@active_end_time = active_end_time
FROM #temp_jobschedule
WHERE (schedule_description = FORMATMESSAGE(14549))
SET ROWCOUNT 0
EXECUTE sp_get_schedule_description
@freq_type,
@freq_interval,
@freq_subday_type,
@freq_subday_interval,
@freq_relative_interval,
@freq_recurrence_factor,
@active_start_date,
@active_end_date,
@active_start_time,
@active_end_time,
@schedule_description OUTPUT
UPDATE #temp_jobschedule
SET schedule_description = ISNULL(LTRIM(RTRIM(@schedule_description)), FORMATMESSAGE(14205))
WHERE (schedule_name = @name)
END -- While
END
END
-- Return the result set, adding job count to it
SELECT *, (SELECT COUNT(*) FROM sysjobschedules WHERE sysjobschedules.schedule_id = #temp_jobschedule.schedule_id) as 'job_count'
FROM #temp_jobschedule
ORDER BY schedule_id
RETURN(@@error) -- 0 means success
END
go
CHECKPOINT
go
/**************************************************************/
/* SP_VERIFY_JOB */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_job...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_job')
AND (type = 'P')))
DROP PROCEDURE sp_verify_job
go
CREATE PROCEDURE sp_verify_job
@job_id UNIQUEIDENTIFIER,
@name sysname,
@enabled TINYINT,
@start_step_id INT,
@category_name sysname,
@owner_sid VARBINARY(85) OUTPUT, -- Output since we may modify it
@notify_level_eventlog INT,
@notify_level_email INT OUTPUT, -- Output since we may reset it to 0
@notify_level_netsend INT OUTPUT, -- Output since we may reset it to 0
@notify_level_page INT OUTPUT, -- Output since we may reset it to 0
@notify_email_operator_name sysname,
@notify_netsend_operator_name sysname,
@notify_page_operator_name sysname,
@delete_level INT,
@category_id INT OUTPUT, -- The ID corresponding to the name
@notify_email_operator_id INT OUTPUT, -- The ID corresponding to the name
@notify_netsend_operator_id INT OUTPUT, -- The ID corresponding to the name
@notify_page_operator_id INT OUTPUT, -- The ID corresponding to the name
@originating_server sysname OUTPUT -- Output since we may modify it
AS
BEGIN
DECLARE @job_type INT
DECLARE @retval INT
DECLARE @current_date INT
DECLARE @res_valid_range NVARCHAR(200)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
SELECT @category_name = LTRIM(RTRIM(@category_name))
SELECT @originating_server = UPPER(LTRIM(RTRIM(@originating_server)))
SELECT @originating_server = ISNULL(@originating_server, UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))
-- Check originating server (only the SQLServerAgent can add jobs that originate from a remote server)
IF (@originating_server <> UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))) AND
(PROGRAM_NAME() NOT LIKE N'SQLAgent%')
BEGIN
RAISERROR(14275, -1, -1)
RETURN(1) -- Failure
END
-- NOTE: We allow jobs with the same name (since job_id is always unique) but only if
-- they originate from different servers. Thus jobs can flow from an MSX to a TSX
-- without having to worry about naming conflicts.
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobs as job
JOIN msdb.dbo.sysoriginatingservers_view as svr
ON (svr.originating_server_id = job.originating_server_id)
WHERE (name = @name)
AND (svr.originating_server = @originating_server)
AND (job_id <> ISNULL(@job_id, 0x911)))) -- When adding a new job @job_id is NULL
BEGIN
RAISERROR(14261, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
-- Check enabled state
IF (@enabled <> 0) AND (@enabled <> 1)
BEGIN
RAISERROR(14266, -1, -1, '@enabled', '0, 1')
RETURN(1) -- Failure
END
-- Check start step
IF (@job_id IS NULL)
BEGIN
-- New job
-- NOTE: For [new] MSX jobs we allow the start step to be other than 1 since
-- the start step was validated when the job was created at the MSX
IF (@start_step_id <> 1) AND (@originating_server = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))
BEGIN
RAISERROR(14266, -1, -1, '@start_step_id', '1')
RETURN(1) -- Failure
END
END
ELSE
BEGIN
-- Existing job
DECLARE @max_step_id INT
DECLARE @valid_range VARCHAR(50)
-- Get current maximum step id
SELECT @max_step_id = ISNULL(MAX(step_id), 0)
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
IF (@start_step_id < 1) OR (@start_step_id > @max_step_id + 1)
BEGIN
SELECT @valid_range = '1..' + CONVERT(VARCHAR, @max_step_id + 1)
RAISERROR(14266, -1, -1, '@start_step_id', @valid_range)
RETURN(1) -- Failure
END
END
-- Check category
SELECT @job_type = NULL
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)))
SELECT @job_type = 1 -- LOCAL
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id <> 0)))
SELECT @job_type = 2 -- MULTI-SERVER
-- A local job cannot be added to a multi-server job_category
IF (@job_type = 1) AND (EXISTS (SELECT *
FROM msdb.dbo.syscategories
WHERE (category_class = 1) -- Job
AND (category_type = 2) -- Multi-Server
AND (name = @category_name)))
BEGIN
RAISERROR(14285, -1, -1)
RETURN(1) -- Failure
END
-- A multi-server job cannot be added to a local job_category
IF (@job_type = 2) AND (EXISTS (SELECT *
FROM msdb.dbo.syscategories
WHERE (category_class = 1) -- Job
AND (category_type = 1) -- Local
AND (name = @category_name)))
BEGIN
RAISERROR(14286, -1, -1)
RETURN(1) -- Failure
END
-- Get the category_id, handling any special-cases as appropriate
SELECT @category_id = NULL
IF (@category_name = N'[DEFAULT]') -- User wants to revert to the default job category
BEGIN
SELECT @category_id = CASE ISNULL(@job_type, 1)
WHEN 1 THEN 0 -- [Uncategorized (Local)]
WHEN 2 THEN 2 -- [Uncategorized (Multi-Server)]
END
END
ELSE
IF (@category_name IS NULL) -- The sp_add_job default
BEGIN
SELECT @category_id = 0
END
ELSE
BEGIN
SELECT @category_id = category_id
FROM msdb.dbo.syscategories
WHERE (category_class = 1) -- Job
AND (name = @category_name)
END
IF (@category_id IS NULL)
BEGIN
RAISERROR(14234, -1, -1, '@category_name', 'sp_help_category')
RETURN(1) -- Failure
END
-- Only SQLServerAgent may add jobs to the 'Jobs From MSX' category
IF (@category_id = 1) AND
(PROGRAM_NAME() NOT LIKE N'SQLAgent%')
BEGIN
RAISERROR(14267, -1, -1, @category_name)
RETURN(1) -- Failure
END
-- Check owner
-- Default the owner to be the calling user if:
-- caller is not a sysadmin
-- caller is not SQLAgentOperator and job_id is NULL, meaning new job
IF (((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND
((ISNULL(IS_MEMBER('SQLAgentOperatorRole'), 0) = 0) AND @job_id IS NULL)) AND
(@owner_sid <> SUSER_SID()))
BEGIN
SELECT @owner_sid = SUSER_SID()
END
-- Now just check that the login id is valid (ie. it exists and isn't an NT group)
IF ((@owner_sid <> 0x010100000000000512000000) AND -- NT AUTHORITY\SYSTEM sid
(@owner_sid <> 0x010100000000000514000000)) OR -- NT AUTHORITY\NETWORK SERVICE sid
(@owner_sid IS NULL)
BEGIN
IF (@owner_sid IS NULL OR (EXISTS (SELECT sid
FROM sys.syslogins
WHERE sid = @owner_sid
AND isntgroup <> 0)))
BEGIN
-- NOTE: In the following message we quote @owner_login_name instead of @owner_sid
-- since this is the parameter the user passed to the calling SP (ie. either
-- sp_add_job or sp_update_job)
SELECT @res_valid_range = FORMATMESSAGE(14203)
RAISERROR(14234, -1, -1, '@owner_login_name', @res_valid_range)
RETURN(1) -- Failure
END
END
-- Check notification levels (must be 0, 1, 2 or 3)
IF (@notify_level_eventlog & 0x3 <> @notify_level_eventlog)
BEGIN
RAISERROR(14266, -1, -1, '@notify_level_eventlog', '0, 1, 2, 3')
RETURN(1) -- Failure
END
IF (@notify_level_email & 0x3 <> @notify_level_email)
BEGIN
RAISERROR(14266, -1, -1, '@notify_level_email', '0, 1, 2, 3')
RETURN(1) -- Failure
END
IF (@notify_level_netsend & 0x3 <> @notify_level_netsend)
BEGIN
RAISERROR(14266, -1, -1, '@notify_level_netsend', '0, 1, 2, 3')
RETURN(1) -- Failure
END
IF (@notify_level_page & 0x3 <> @notify_level_page)
BEGIN
RAISERROR(14266, -1, -1, '@notify_level_page', '0, 1, 2, 3')
RETURN(1) -- Failure
END
-- If we're at a TSX, only SQLServerAgent may add jobs that notify 'MSXOperator'
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.systargetservers)) AND
((@notify_email_operator_name = N'MSXOperator') OR
(@notify_page_operator_name = N'MSXOperator') OR
(@notify_netsend_operator_name = N'MSXOperator')) AND
(PROGRAM_NAME() NOT LIKE N'SQLAgent%')
BEGIN
RAISERROR(14251, -1, -1, 'MSXOperator')
RETURN(1) -- Failure
END
-- Check operator to notify (via email)
IF (@notify_email_operator_name IS NOT NULL)
BEGIN
SELECT @notify_email_operator_id = id
FROM msdb.dbo.sysoperators
WHERE (name = @notify_email_operator_name)
IF (@notify_email_operator_id IS NULL)
BEGIN
RAISERROR(14234, -1, -1, '@notify_email_operator_name', 'sp_help_operator')
RETURN(1) -- Failure
END
-- If a valid operator is specified the level must be non-zero
IF (@notify_level_email = 0)
BEGIN
RAISERROR(14266, -1, -1, '@notify_level_email', '1, 2, 3')
RETURN(1) -- Failure
END
END
ELSE
BEGIN
SELECT @notify_email_operator_id = 0
SELECT @notify_level_email = 0
END
-- Check operator to notify (via netsend)
IF (@notify_netsend_operator_name IS NOT NULL)
BEGIN
SELECT @notify_netsend_operator_id = id
FROM msdb.dbo.sysoperators
WHERE (name = @notify_netsend_operator_name)
IF (@notify_netsend_operator_id IS NULL)
BEGIN
RAISERROR(14234, -1, -1, '@notify_netsend_operator_name', 'sp_help_operator')
RETURN(1) -- Failure
END
-- If a valid operator is specified the level must be non-zero
IF (@notify_level_netsend = 0)
BEGIN
RAISERROR(14266, -1, -1, '@notify_level_netsend', '1, 2, 3')
RETURN(1) -- Failure
END
END
ELSE
BEGIN
SELECT @notify_netsend_operator_id = 0
SELECT @notify_level_netsend = 0
END
-- Check operator to notify (via page)
IF (@notify_page_operator_name IS NOT NULL)
BEGIN
SELECT @notify_page_operator_id = id
FROM msdb.dbo.sysoperators
WHERE (name = @notify_page_operator_name)
IF (@notify_page_operator_id IS NULL)
BEGIN
RAISERROR(14234, -1, -1, '@notify_page_operator_name', 'sp_help_operator')
RETURN(1) -- Failure
END
-- If a valid operator is specified the level must be non-zero
IF (@notify_level_page = 0)
BEGIN
RAISERROR(14266, -1, -1, '@notify_level_page', '1, 2, 3')
RETURN(1) -- Failure
END
END
ELSE
BEGIN
SELECT @notify_page_operator_id = 0
SELECT @notify_level_page = 0
END
-- Check delete level (must be 0, 1, 2 or 3)
IF (@delete_level & 0x3 <> @delete_level)
BEGIN
RAISERROR(14266, -1, -1, '@delete_level', '0, 1, 2, 3')
RETURN(1) -- Failure
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_ADD_JOB */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_job...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_job')
AND (type = 'P')))
DROP PROCEDURE sp_add_job
go
CREATE PROCEDURE sp_add_job
@job_name sysname,
@enabled TINYINT = 1, -- 0 = Disabled, 1 = Enabled
@description NVARCHAR(512) = NULL,
@start_step_id INT = 1,
@category_name sysname = NULL,
@category_id INT = NULL, -- A language-independent way to specify which category to use
@owner_login_name sysname = NULL, -- The procedure assigns a default
@notify_level_eventlog INT = 2, -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
@notify_level_email INT = 0, -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
@notify_level_netsend INT = 0, -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
@notify_level_page INT = 0, -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
@notify_email_operator_name sysname = NULL,
@notify_netsend_operator_name sysname = NULL,
@notify_page_operator_name sysname = NULL,
@delete_level INT = 0, -- 0 = Never, 1 = On Success, 2 = On Failure, 3 = Always
@job_id UNIQUEIDENTIFIER = NULL OUTPUT,
@originating_server sysname = NULL -- For SQLAgent use only
AS
BEGIN
DECLARE @retval INT
DECLARE @notify_email_operator_id INT
DECLARE @notify_netsend_operator_id INT
DECLARE @notify_page_operator_id INT
DECLARE @owner_sid VARBINARY(85)
DECLARE @originating_server_id INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters (except @owner_login_name)
SELECT @originating_server = UPPER(LTRIM(RTRIM(@originating_server)))
SELECT @job_name = LTRIM(RTRIM(@job_name))
SELECT @description = LTRIM(RTRIM(@description))
SELECT @category_name = LTRIM(RTRIM(@category_name))
SELECT @notify_email_operator_name = LTRIM(RTRIM(@notify_email_operator_name))
SELECT @notify_netsend_operator_name = LTRIM(RTRIM(@notify_netsend_operator_name))
SELECT @notify_page_operator_name = LTRIM(RTRIM(@notify_page_operator_name))
SELECT @originating_server_id = NULL
-- Turn [nullable] empty string parameters into NULLs
IF (@originating_server = N'') SELECT @originating_server = NULL
IF (@description = N'') SELECT @description = NULL
IF (@category_name = N'') SELECT @category_name = NULL
IF (@notify_email_operator_name = N'') SELECT @notify_email_operator_name = NULL
IF (@notify_netsend_operator_name = N'') SELECT @notify_netsend_operator_name = NULL
IF (@notify_page_operator_name = N'') SELECT @notify_page_operator_name = NULL
IF (@originating_server IS NULL) OR (@originating_server = '(LOCAL)')
SELECT @originating_server= UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))
--only members of sysadmins role can set the owner
IF (@owner_login_name IS NOT NULL AND ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND (@owner_login_name <> SUSER_SNAME())
BEGIN
RAISERROR(14515, -1, -1)
RETURN(1) -- Failure
END
-- Default the owner (if not supplied or if a non-sa is [illegally] trying to create a job for another user)
-- allow special account only when caller is sysadmin
IF (@owner_login_name = N'$(SQLAgentAccount)') AND
(ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
BEGIN
SELECT @owner_sid = 0xFFFFFFFF
END
ELSE
IF (@owner_login_name IS NULL) OR ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) AND (@owner_login_name <> SUSER_SNAME()))
BEGIN
SELECT @owner_sid = SUSER_SID()
END
ELSE
BEGIN
--force case insensitive comparation for NT users
SELECT @owner_sid = SUSER_SID(@owner_login_name, 0) -- If @owner_login_name is invalid then SUSER_SID() will return NULL
END
-- Default the description (if not supplied)
IF (@description IS NULL)
SELECT @description = FORMATMESSAGE(14571)
-- If a category ID is provided this overrides any supplied category name
EXECUTE @retval = sp_verify_category_identifiers '@category_name',
'@category_id',
@category_name OUTPUT,
@category_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check parameters
EXECUTE @retval = sp_verify_job NULL, -- The job id is null since this is a new job
@job_name,
@enabled,
@start_step_id,
@category_name,
@owner_sid OUTPUT,
@notify_level_eventlog,
@notify_level_email OUTPUT,
@notify_level_netsend OUTPUT,
@notify_level_page OUTPUT,
@notify_email_operator_name,
@notify_netsend_operator_name,
@notify_page_operator_name,
@delete_level,
@category_id OUTPUT,
@notify_email_operator_id OUTPUT,
@notify_netsend_operator_id OUTPUT,
@notify_page_operator_id OUTPUT,
@originating_server OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
SELECT @originating_server_id = originating_server_id
FROM msdb.dbo.sysoriginatingservers_view
WHERE (originating_server = @originating_server)
IF (@originating_server_id IS NULL)
BEGIN
RAISERROR(14370, -1, -1)
RETURN(1) -- Failure
END
IF (@job_id IS NULL)
BEGIN
-- Assign the GUID
SELECT @job_id = NEWID()
END
ELSE
BEGIN
-- A job ID has been provided, so check that the caller is SQLServerAgent (inserting an MSX job)
IF (PROGRAM_NAME() NOT LIKE N'SQLAgent%')
BEGIN
RAISERROR(14274, -1, -1)
RETURN(1) -- Failure
END
END
INSERT INTO msdb.dbo.sysjobs
(job_id,
originating_server_id,
name,
enabled,
description,
start_step_id,
category_id,
owner_sid,
notify_level_eventlog,
notify_level_email,
notify_level_netsend,
notify_level_page,
notify_email_operator_id,
notify_netsend_operator_id,
notify_page_operator_id,
delete_level,
date_created,
date_modified,
version_number)
VALUES (@job_id,
@originating_server_id,
@job_name,
@enabled,
@description,
@start_step_id,
@category_id,
@owner_sid,
@notify_level_eventlog,
@notify_level_email,
@notify_level_netsend,
@notify_level_page,
@notify_email_operator_id,
@notify_netsend_operator_id,
@notify_page_operator_id,
@delete_level,
GETDATE(),
GETDATE(),
1) -- Version number 1
SELECT @retval = @@error
-- NOTE: We don't notify SQLServerAgent to update it's cache (we'll do this in sp_add_jobserver)
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_UPDATE_JOB */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_job...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_update_job')
AND (type = 'P')))
DROP PROCEDURE sp_update_job
go
CREATE PROCEDURE sp_update_job
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide this or current_name
@job_name sysname = NULL, -- Must provide this or job_id
@new_name sysname = NULL,
@enabled TINYINT = NULL,
@description NVARCHAR(512) = NULL,
@start_step_id INT = NULL,
@category_name sysname = NULL,
@owner_login_name sysname = NULL,
@notify_level_eventlog INT = NULL,
@notify_level_email INT = NULL,
@notify_level_netsend INT = NULL,
@notify_level_page INT = NULL,
@notify_email_operator_name sysname = NULL,
@notify_netsend_operator_name sysname = NULL,
@notify_page_operator_name sysname = NULL,
@delete_level INT = NULL,
@automatic_post BIT = 1 -- Flag for SEM use only
AS
BEGIN
DECLARE @retval INT
DECLARE @category_id INT
DECLARE @notify_email_operator_id INT
DECLARE @notify_netsend_operator_id INT
DECLARE @notify_page_operator_id INT
DECLARE @owner_sid VARBINARY(85)
DECLARE @alert_id INT
DECLARE @cached_attribute_modified INT
DECLARE @is_sysadmin INT
DECLARE @current_owner sysname
DECLARE @enable_only_used INT
DECLARE @x_new_name sysname
DECLARE @x_enabled TINYINT
DECLARE @x_description NVARCHAR(512)
DECLARE @x_start_step_id INT
DECLARE @x_category_name sysname
DECLARE @x_category_id INT
DECLARE @x_owner_sid VARBINARY(85)
DECLARE @x_notify_level_eventlog INT
DECLARE @x_notify_level_email INT
DECLARE @x_notify_level_netsend INT
DECLARE @x_notify_level_page INT
DECLARE @x_notify_email_operator_name sysname
DECLARE @x_notify_netsnd_operator_name sysname
DECLARE @x_notify_page_operator_name sysname
DECLARE @x_delete_level INT
DECLARE @x_originating_server_id INT -- Not updatable
DECLARE @x_master_server BIT
-- Remove any leading/trailing spaces from parameters (except @owner_login_name)
SELECT @job_name = LTRIM(RTRIM(@job_name))
SELECT @new_name = LTRIM(RTRIM(@new_name))
SELECT @description = LTRIM(RTRIM(@description))
SELECT @category_name = LTRIM(RTRIM(@category_name))
SELECT @notify_email_operator_name = LTRIM(RTRIM(@notify_email_operator_name))
SELECT @notify_netsend_operator_name = LTRIM(RTRIM(@notify_netsend_operator_name))
SELECT @notify_page_operator_name = LTRIM(RTRIM(@notify_page_operator_name))
SET NOCOUNT ON
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Are we modifying an attribute which SQLServerAgent caches?
IF ((@new_name IS NOT NULL) OR
(@enabled IS NOT NULL) OR
(@start_step_id IS NOT NULL) OR
(@owner_login_name IS NOT NULL) OR
(@notify_level_eventlog IS NOT NULL) OR
(@notify_level_email IS NOT NULL) OR
(@notify_level_netsend IS NOT NULL) OR
(@notify_level_page IS NOT NULL) OR
(@notify_email_operator_name IS NOT NULL) OR
(@notify_netsend_operator_name IS NOT NULL) OR
(@notify_page_operator_name IS NOT NULL) OR
(@delete_level IS NOT NULL))
SELECT @cached_attribute_modified = 1
ELSE
SELECT @cached_attribute_modified = 0
-- Is @enable the only parameter used beside jobname and jobid?
IF ((@enabled IS NOT NULL) AND
(@new_name IS NULL) AND
(@description IS NULL) AND
(@start_step_id IS NULL) AND
(@category_name IS NULL) AND
(@owner_login_name IS NULL) AND
(@notify_level_eventlog IS NULL) AND
(@notify_level_email IS NULL) AND
(@notify_level_netsend IS NULL) AND
(@notify_level_page IS NULL) AND
(@notify_email_operator_name IS NULL) AND
(@notify_netsend_operator_name IS NULL) AND
(@notify_page_operator_name IS NULL) AND
(@delete_level IS NULL))
SELECT @enable_only_used = 1
ELSE
SELECT @enable_only_used = 0
-- Set the x_ (existing) variables
SELECT @x_new_name = sjv.name,
@x_enabled = sjv.enabled,
@x_description = sjv.description,
@x_start_step_id = sjv.start_step_id,
@x_category_name = sc.name, -- From syscategories
@x_category_id = sc.category_id, -- From syscategories
@x_owner_sid = sjv.owner_sid,
@x_notify_level_eventlog = sjv.notify_level_eventlog,
@x_notify_level_email = sjv.notify_level_email,
@x_notify_level_netsend = sjv.notify_level_netsend,
@x_notify_level_page = sjv.notify_level_page,
@x_notify_email_operator_name = so1.name, -- From sysoperators
@x_notify_netsnd_operator_name = so2.name, -- From sysoperators
@x_notify_page_operator_name = so3.name, -- From sysoperators
@x_delete_level = sjv.delete_level,
@x_originating_server_id = sjv.originating_server_id,
@x_master_server = master_server
FROM msdb.dbo.sysjobs_view sjv
LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjv.notify_email_operator_id = so1.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjv.notify_netsend_operator_id = so2.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjv.notify_page_operator_id = so3.id),
msdb.dbo.syscategories sc
WHERE (sjv.job_id = @job_id)
AND (sjv.category_id = sc.category_id)
-- Check authority (only SQLServerAgent can modify a non-local job)
IF ((@x_master_server = 1) AND (PROGRAM_NAME() NOT LIKE N'SQLAgent%') )
BEGIN
RAISERROR(14274, -1, -1)
RETURN(1) -- Failure
END
-- Check permissions beyond what's checked by the sysjobs_view
-- SQLAgentReader and SQLAgentOperator roles that can see all jobs
-- cannot modify jobs they do not own
IF ( (@x_owner_sid <> SUSER_SID()) -- does not own the job
AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1) -- is not sysadmin
AND (@enable_only_used <> 1 OR ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) <> 1))
BEGIN
RAISERROR(14525, -1, -1);
RETURN(1) -- Failure
END
-- Check job category, only sysadmin can modify mutli-server jobs
IF (EXISTS (SELECT * FROM msdb.dbo.syscategories WHERE (category_class = 1) -- Job
AND (category_type = 2) -- Multi-Server
AND (category_id = @x_category_id)
AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))) -- is not sysadmin
BEGIN
RAISERROR(14396, -1, -1);
RETURN(1) -- Failure
END
IF (@new_name = N'') SELECT @new_name = NULL
-- Fill out the values for all non-supplied parameters from the existing values
IF (@new_name IS NULL) SELECT @new_name = @x_new_name
IF (@enabled IS NULL) SELECT @enabled = @x_enabled
IF (@description IS NULL) SELECT @description = @x_description
IF (@start_step_id IS NULL) SELECT @start_step_id = @x_start_step_id
IF (@category_name IS NULL) SELECT @category_name = @x_category_name
IF (@owner_sid IS NULL) SELECT @owner_sid = @x_owner_sid
IF (@notify_level_eventlog IS NULL) SELECT @notify_level_eventlog = @x_notify_level_eventlog
IF (@notify_level_email IS NULL) SELECT @notify_level_email = @x_notify_level_email
IF (@notify_level_netsend IS NULL) SELECT @notify_level_netsend = @x_notify_level_netsend
IF (@notify_level_page IS NULL) SELECT @notify_level_page = @x_notify_level_page
IF (@notify_email_operator_name IS NULL) SELECT @notify_email_operator_name = @x_notify_email_operator_name
IF (@notify_netsend_operator_name IS NULL) SELECT @notify_netsend_operator_name = @x_notify_netsnd_operator_name
IF (@notify_page_operator_name IS NULL) SELECT @notify_page_operator_name = @x_notify_page_operator_name
IF (@delete_level IS NULL) SELECT @delete_level = @x_delete_level
-- If the SA is attempting to assign ownership of the job to someone else, then convert
-- the login name to an ID
IF (@owner_login_name = N'$(SQLAgentAccount)') AND
(ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
BEGIN
SELECT @owner_sid = 0xFFFFFFFF
END
ELSE IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) AND (@owner_login_name IS NOT NULL))
BEGIN
--force case insensitive comparation for NT users
SELECT @owner_sid = SUSER_SID(@owner_login_name, 0) -- If @owner_login_name is invalid then SUSER_SID() will return NULL
END
-- Only the SA can re-assign jobs
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1) AND (@owner_login_name IS NOT NULL))
RAISERROR(14242, -1, -1)
-- Ownership of a multi-server job cannot be assigned to a non-sysadmin
IF (@owner_login_name IS NOT NULL) AND
(EXISTS (SELECT *
FROM msdb.dbo.sysjobs sj,
msdb.dbo.sysjobservers sjs
WHERE (sj.job_id = sjs.job_id)
AND (sj.job_id = @job_id)
AND (sjs.server_id <> 0)))
BEGIN
IF (@owner_login_name = N'$(SQLAgentAccount)') -- allow distributed jobs to be assigned to special account
BEGIN
SELECT @is_sysadmin = 1
END
ELSE
BEGIN
SELECT @is_sysadmin = 0
EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @owner_login_name, @is_sysadmin_member = @is_sysadmin OUTPUT
END
IF (@is_sysadmin = 0)
BEGIN
SELECT @current_owner = dbo.SQLAGENT_SUSER_SNAME(@x_owner_sid)
RAISERROR(14543, -1, -1, @current_owner, N'sysadmin')
RETURN(1) -- Failure
END
END
-- Turn [nullable] empty string parameters into NULLs
IF (@description = N'') SELECT @description = NULL
IF (@category_name = N'') SELECT @category_name = NULL
IF (@notify_email_operator_name = N'') SELECT @notify_email_operator_name = NULL
IF (@notify_netsend_operator_name = N'') SELECT @notify_netsend_operator_name = NULL
IF (@notify_page_operator_name = N'') SELECT @notify_page_operator_name = NULL
-- Check new values
EXECUTE @retval = sp_verify_job @job_id,
@new_name,
@enabled,
@start_step_id,
@category_name,
@owner_sid OUTPUT,
@notify_level_eventlog,
@notify_level_email OUTPUT,
@notify_level_netsend OUTPUT,
@notify_level_page OUTPUT,
@notify_email_operator_name,
@notify_netsend_operator_name,
@notify_page_operator_name,
@delete_level,
@category_id OUTPUT,
@notify_email_operator_id OUTPUT,
@notify_netsend_operator_id OUTPUT,
@notify_page_operator_id OUTPUT,
NULL
IF (@retval <> 0)
RETURN(1) -- Failure
BEGIN TRANSACTION
-- If the job is being re-assigned, modify sysjobsteps.database_user_name as necessary
IF (@owner_login_name IS NOT NULL)
BEGIN
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND (subsystem = N'TSQL')))
BEGIN
IF (EXISTS (SELECT *
FROM master.dbo.syslogins
WHERE (sid = @owner_sid)
AND (sysadmin <> 1)))
BEGIN
-- The job is being re-assigned to an non-SA
UPDATE msdb.dbo.sysjobsteps
SET database_user_name = NULL
WHERE (job_id = @job_id)
AND (subsystem = N'TSQL')
END
END
END
UPDATE msdb.dbo.sysjobs
SET name = @new_name,
enabled = @enabled,
description = @description,
start_step_id = @start_step_id,
category_id = @category_id, -- Returned from sp_verify_job
owner_sid = @owner_sid,
notify_level_eventlog = @notify_level_eventlog,
notify_level_email = @notify_level_email,
notify_level_netsend = @notify_level_netsend,
notify_level_page = @notify_level_page,
notify_email_operator_id = @notify_email_operator_id, -- Returned from sp_verify_job
notify_netsend_operator_id = @notify_netsend_operator_id, -- Returned from sp_verify_job
notify_page_operator_id = @notify_page_operator_id, -- Returned from sp_verify_job
delete_level = @delete_level,
version_number = version_number + 1, -- Update the job's version
date_modified = GETDATE() -- Update the job's last-modified information
WHERE (job_id = @job_id)
SELECT @retval = @@error
COMMIT TRANSACTION
-- Always re-post the job if it's an auto-delete job (or if we're updating an auto-delete job
-- to be non-auto-delete)
IF (((SELECT delete_level
FROM msdb.dbo.sysjobs
WHERE (job_id = @job_id)) <> 0) OR
((@x_delete_level = 1) AND (@delete_level = 0)))
EXECUTE msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id
ELSE
BEGIN
-- Post the update to target servers
IF (@automatic_post = 1)
EXECUTE msdb.dbo.sp_post_msx_operation 'UPDATE', 'JOB', @job_id
END
-- Keep SQLServerAgent's cache in-sync
-- NOTE: We only notify SQLServerAgent if we know the job has been cached and if
-- attributes other than description or category have been changed (since
-- SQLServerAgent doesn't cache these two)
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)
AND (@cached_attribute_modified = 1)))
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'J',
@job_id = @job_id,
@action_type = N'U'
-- If the name was changed, make SQLServerAgent re-cache any alerts that reference the job
-- since the alert cache contains the job name
IF ((@job_name <> @new_name) AND (EXISTS (SELECT *
FROM msdb.dbo.sysalerts
WHERE (job_id = @job_id))))
BEGIN
DECLARE sysalerts_cache_update CURSOR LOCAL
FOR
SELECT id
FROM msdb.dbo.sysalerts
WHERE (job_id = @job_id)
OPEN sysalerts_cache_update
FETCH NEXT FROM sysalerts_cache_update INTO @alert_id
WHILE (@@fetch_status = 0)
BEGIN
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',
@alert_id = @alert_id,
@action_type = N'U'
FETCH NEXT FROM sysalerts_cache_update INTO @alert_id
END
DEALLOCATE sysalerts_cache_update
END
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_DELETE_JOB */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_job...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_job')
AND (type = 'P')))
DROP PROCEDURE sp_delete_job
go
CREATE PROCEDURE sp_delete_job
@job_id UNIQUEIDENTIFIER = NULL, -- If provided should NOT also provide job_name
@job_name sysname = NULL, -- If provided should NOT also provide job_id
@originating_server sysname = NULL, -- Reserved (used by SQLAgent)
@delete_history BIT = 1, -- Reserved (used by SQLAgent)
@delete_unused_schedule BIT = 1 -- For backward compatibility schedules are deleted by default if they are not
-- being used by another job. With the introduction of reusable schedules in V9
-- callers should set this to 0 so the schedule will be preserved for reuse.
AS
BEGIN
DECLARE @current_msx_server sysname
DECLARE @bMSX_job BIT
DECLARE @retval INT
DECLARE @local_machine_name sysname
DECLARE @category_id INT
DECLARE @job_owner_sid VARBINARY(85)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @originating_server = UPPER(LTRIM(RTRIM(@originating_server)))
-- Turn [nullable] empty string parameters into NULLs
IF (@originating_server = N'') SELECT @originating_server = NULL
-- Change server name to always reflect real servername or servername\instancename
IF (@originating_server IS NOT NULL AND @originating_server = '(LOCAL)')
SELECT @originating_server = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))
IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
BEGIN
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- We need either a job name or a server name, not both
IF ((@job_name IS NULL) AND (@originating_server IS NULL)) OR
((@job_name IS NOT NULL) AND (@originating_server IS NOT NULL))
BEGIN
RAISERROR(14279, -1, -1)
RETURN(1) -- Failure
END
-- Get category to see if it is a misc. replication agent. @category_id will be
-- NULL if there is no @job_id.
select @category_id = category_id from msdb.dbo.sysjobs where job_id = @job_id
-- If job name was given, determine if the job is from an MSX
IF (@job_id IS NOT NULL)
BEGIN
SELECT @bMSX_job = CASE UPPER(originating_server)
WHEN UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))) THEN 0
ELSE 1
END
FROM msdb.dbo.sysjobs_view
WHERE (job_id = @job_id)
END
-- If server name was given, warn user if different from current MSX
IF (@originating_server IS NOT NULL)
BEGIN
EXECUTE @retval = master.dbo.xp_getnetname @local_machine_name OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
IF ((@originating_server = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))) OR (@originating_server = UPPER(@local_machine_name)))
SELECT @originating_server = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServerName',
@current_msx_server OUTPUT,
N'no_output'
SELECT @current_msx_server = UPPER(@current_msx_server)
-- If server name was given but it's not the current MSX, print a warning
SELECT @current_msx_server = LTRIM(RTRIM(@current_msx_server))
IF ((@current_msx_server IS NOT NULL) AND (@current_msx_server <> N'') AND (@originating_server <> @current_msx_server))
RAISERROR(14224, 0, 1, @current_msx_server)
END
-- Check authority (only SQLServerAgent can delete a non-local job)
IF (((@originating_server IS NOT NULL) AND (@originating_server <> UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))) OR (@bMSX_job = 1)) AND
(PROGRAM_NAME() NOT LIKE N'SQLAgent%')
BEGIN
RAISERROR(14274, -1, -1)
RETURN(1) -- Failure
END
-- Check permissions beyond what's checked by the sysjobs_view
-- SQLAgentReader and SQLAgentOperator roles that can see all jobs
-- cannot delete jobs they do not own
IF (@job_id IS NOT NULL)
BEGIN
IF (@job_owner_sid <> SUSER_SID() -- does not own the job
AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)) -- is not sysadmin
BEGIN
RAISERROR(14525, -1, -1);
RETURN(1) -- Failure
END
END
-- Do the delete (for a specific job)
IF (@job_id IS NOT NULL)
BEGIN
-- Note: This temp table is referenced by msdb.dbo.sp_delete_job_references,
-- so it cannot be declared as a local table.
CREATE TABLE #temp_jobs_to_delete (job_id UNIQUEIDENTIFIER NOT NULL PRIMARY KEY CLUSTERED,
job_is_cached INT NOT NULL)
DECLARE @temp_schedules_to_delete TABLE (schedule_id INT NOT NULL)
INSERT INTO #temp_jobs_to_delete
SELECT job_id, (SELECT COUNT(*)
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0))
FROM msdb.dbo.sysjobs_view
WHERE (job_id = @job_id)
-- Check if we have any work to do
IF (NOT EXISTS (SELECT *
FROM #temp_jobs_to_delete))
BEGIN
DROP TABLE #temp_jobs_to_delete
RETURN(0) -- Success
END
-- Post the delete to any target servers (need to do this BEFORE
-- deleting the job itself, but AFTER clearing all all pending
-- download instructions). Note that if the job is NOT a
-- multi-server job then sp_post_msx_operation will catch this and
-- will do nothing. Since it will do nothing that is why we need
-- to NOT delete any pending delete requests, because that delete
-- request might have been for the last target server and thus
-- this job isn't a multi-server job anymore so posting the global
-- delete would do nothing.
DELETE FROM msdb.dbo.sysdownloadlist
WHERE (object_id = @job_id)
and (operation_code != 3) -- Delete
EXECUTE msdb.dbo.sp_post_msx_operation 'DELETE', 'JOB', @job_id
-- Must do this before deleting the job itself since sp_sqlagent_notify does a lookup on sysjobs_view
-- Note: Don't notify agent in this call. It is done after the transaction is committed
-- just in case this job is in the process of deleting itself
EXECUTE msdb.dbo.sp_delete_job_references @notify_sqlagent = 0
-- Delete all traces of the job
BEGIN TRANSACTION
DECLARE @err int
--Get the schedules to delete before deleting records from sysjobschedules
IF(@delete_unused_schedule = 1)
BEGIN
--Get the list of schedules to delete
INSERT INTO @temp_schedules_to_delete
SELECT DISTINCT schedule_id
FROM msdb.dbo.sysschedules
WHERE (schedule_id IN
(SELECT schedule_id
FROM msdb.dbo.sysjobschedules
WHERE (job_id = @job_id)))
END
DELETE FROM msdb.dbo.sysjobschedules
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
DELETE FROM msdb.dbo.sysjobservers
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
DELETE FROM msdb.dbo.sysjobsteps
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
DELETE FROM msdb.dbo.sysjobs
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
SELECT @err = @@ERROR
IF @err <> 0
BEGIN
ROLLBACK TRANSACTION
RETURN @err
END
--Delete the schedule(s) if requested to and it isn't being used by other jobs
IF(@delete_unused_schedule = 1)
BEGIN
--Now OK to delete the schedule
DELETE FROM msdb.dbo.sysschedules
WHERE schedule_id IN
(SELECT schedule_id
FROM @temp_schedules_to_delete as sdel
WHERE NOT EXISTS(SELECT *
FROM msdb.dbo.sysjobschedules AS js
WHERE (js.schedule_id = sdel.schedule_id)))
END
-- Delete the job history if requested
IF (@delete_history = 1)
BEGIN
DELETE FROM msdb.dbo.sysjobhistory
WHERE job_id IN (SELECT job_id FROM #temp_jobs_to_delete)
END
-- All done
COMMIT TRANSACTION
-- Now notify agent to delete the job.
IF(EXISTS(SELECT * FROM #temp_jobs_to_delete WHERE job_is_cached > 0))
BEGIN
DECLARE @nt_user_name NVARCHAR(100)
SELECT @nt_user_name = ISNULL(NT_CLIENT(), ISNULL(SUSER_SNAME(), FORMATMESSAGE(14205)))
--Call the xp directly. sp_sqlagent_notify checks sysjobs_view and the record has already been deleted
EXEC master.dbo.xp_sqlagent_notify N'J', @job_id, 0, 0, N'D', @nt_user_name, 1, @@trancount, NULL, NULL
END
END
ELSE
-- Do the delete (for all jobs originating from the specific server)
IF (@originating_server IS NOT NULL)
BEGIN
EXECUTE msdb.dbo.sp_delete_all_msx_jobs @msx_server = @originating_server
-- NOTE: In this case there is no need to propagate the delete via sp_post_msx_operation
-- since this type of delete is only ever performed on a TSX.
END
IF (OBJECT_ID(N'tempdb.dbo.#temp_jobs_to_delete', 'U') IS NOT NULL)
DROP TABLE #temp_jobs_to_delete
RETURN(0) -- 0 means success
END
go
/**************************************************************/
/* SP_GET_COMPOSITE_JOB_INFO */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_get_composite_job_info...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_get_composite_job_info')
AND (type = 'P')))
DROP PROCEDURE sp_get_composite_job_info
go
CREATE PROCEDURE sp_get_composite_job_info
@job_id UNIQUEIDENTIFIER = NULL,
@job_type VARCHAR(12) = NULL, -- LOCAL or MULTI-SERVER
@owner_login_name sysname = NULL,
@subsystem NVARCHAR(40) = NULL,
@category_id INT = NULL,
@enabled TINYINT = NULL,
@execution_status INT = NULL, -- 0 = Not idle or suspended, 1 = Executing, 2 = Waiting For Thread, 3 = Between Retries, 4 = Idle, 5 = Suspended, [6 = WaitingForStepToFinish], 7 = PerformingCompletionActions
@date_comparator CHAR(1) = NULL, -- >, < or =
@date_created DATETIME = NULL,
@date_last_modified DATETIME = NULL,
@description NVARCHAR(512) = NULL, -- We do a LIKE on this so it can include wildcards
@schedule_id INT = NULL -- if supplied only return the jobs that use this schedule
AS
BEGIN
DECLARE @can_see_all_running_jobs INT
DECLARE @job_owner sysname
SET NOCOUNT ON
-- By 'composite' we mean a combination of sysjobs and xp_sqlagent_enum_jobs data.
-- This proc should only ever be called by sp_help_job, so we don't verify the
-- parameters (sp_help_job has already done this).
-- Step 1: Create intermediate work tables
DECLARE @job_execution_state TABLE (job_id UNIQUEIDENTIFIER NOT NULL,
date_started INT NOT NULL,
time_started INT NOT NULL,
execution_job_status INT NOT NULL,
execution_step_id INT NULL,
execution_step_name sysname COLLATE database_default NULL,
execution_retry_attempt INT NOT NULL,
next_run_date INT NOT NULL,
next_run_time INT NOT NULL,
next_run_schedule_id INT NOT NULL)
DECLARE @filtered_jobs TABLE (job_id UNIQUEIDENTIFIER NOT NULL,
date_created DATETIME NOT NULL,
date_last_modified DATETIME NOT NULL,
current_execution_status INT NULL,
current_execution_step sysname COLLATE database_default NULL,
current_retry_attempt INT NULL,
last_run_date INT NOT NULL,
last_run_time INT NOT NULL,
last_run_outcome INT NOT NULL,
next_run_date INT NULL,
next_run_time INT NULL,
next_run_schedule_id INT NULL,
type INT NOT NULL)
DECLARE @xp_results TABLE (job_id UNIQUEIDENTIFIER NOT NULL,
last_run_date INT NOT NULL,
last_run_time INT NOT NULL,
next_run_date INT NOT NULL,
next_run_time INT NOT NULL,
next_run_schedule_id INT NOT NULL,
requested_to_run INT NOT NULL, -- BOOL
request_source INT NOT NULL,
request_source_id sysname COLLATE database_default NULL,
running INT NOT NULL, -- BOOL
current_step INT NOT NULL,
current_retry_attempt INT NOT NULL,
job_state INT NOT NULL)
-- Step 2: Capture job execution information (for local jobs only since that's all SQLServerAgent caches)
SELECT @can_see_all_running_jobs = ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0)
IF (@can_see_all_running_jobs = 0)
BEGIN
SELECT @can_see_all_running_jobs = ISNULL(IS_MEMBER(N'SQLAgentReaderRole'), 0)
END
SELECT @job_owner = SUSER_SNAME()
IF ((@@microsoftversion / 0x01000000) >= 8) -- SQL Server 8.0 or greater
INSERT INTO @xp_results
EXECUTE master.dbo.xp_sqlagent_enum_jobs @can_see_all_running_jobs, @job_owner, @job_id
ELSE
INSERT INTO @xp_results
EXECUTE master.dbo.xp_sqlagent_enum_jobs @can_see_all_running_jobs, @job_owner
INSERT INTO @job_execution_state
SELECT xpr.job_id,
xpr.last_run_date,
xpr.last_run_time,
xpr.job_state,
sjs.step_id,
sjs.step_name,
xpr.current_retry_attempt,
xpr.next_run_date,
xpr.next_run_time,
xpr.next_run_schedule_id
FROM @xp_results xpr
LEFT OUTER JOIN msdb.dbo.sysjobsteps sjs ON ((xpr.job_id = sjs.job_id) AND (xpr.current_step = sjs.step_id)),
msdb.dbo.sysjobs_view sjv
WHERE (sjv.job_id = xpr.job_id)
-- Step 3: Filter on everything but dates and job_type
IF ((@subsystem IS NULL) AND
(@owner_login_name IS NULL) AND
(@enabled IS NULL) AND
(@category_id IS NULL) AND
(@execution_status IS NULL) AND
(@description IS NULL) AND
(@job_id IS NULL))
BEGIN
-- Optimize for the frequently used case...
INSERT INTO @filtered_jobs
SELECT sjv.job_id,
sjv.date_created,
sjv.date_modified,
ISNULL(jes.execution_job_status, 4), -- Will be NULL if the job is non-local or is not in @job_execution_state (NOTE: 4 = STATE_IDLE)
CASE ISNULL(jes.execution_step_id, 0)
WHEN 0 THEN NULL -- Will be NULL if the job is non-local or is not in @job_execution_state
ELSE CONVERT(NVARCHAR, jes.execution_step_id) + N' (' + jes.execution_step_name + N')'
END,
jes.execution_retry_attempt, -- Will be NULL if the job is non-local or is not in @job_execution_state
0, -- last_run_date placeholder (we'll fix it up in step 3.3)
0, -- last_run_time placeholder (we'll fix it up in step 3.3)
5, -- last_run_outcome placeholder (we'll fix it up in step 3.3 - NOTE: We use 5 just in case there are no jobservers for the job)
jes.next_run_date, -- Will be NULL if the job is non-local or is not in @job_execution_state
jes.next_run_time, -- Will be NULL if the job is non-local or is not in @job_execution_state
jes.next_run_schedule_id, -- Will be NULL if the job is non-local or is not in @job_execution_state
0 -- type placeholder (we'll fix it up in step 3.4)
FROM msdb.dbo.sysjobs_view sjv
LEFT OUTER JOIN @job_execution_state jes ON (sjv.job_id = jes.job_id)
WHERE ((@schedule_id IS NULL)
OR (EXISTS(SELECT *
FROM sysjobschedules as js
WHERE (sjv.job_id = js.job_id)
AND (js.schedule_id = @schedule_id))))
END
ELSE
BEGIN
INSERT INTO @filtered_jobs
SELECT DISTINCT
sjv.job_id,
sjv.date_created,
sjv.date_modified,
ISNULL(jes.execution_job_status, 4), -- Will be NULL if the job is non-local or is not in @job_execution_state (NOTE: 4 = STATE_IDLE)
CASE ISNULL(jes.execution_step_id, 0)
WHEN 0 THEN NULL -- Will be NULL if the job is non-local or is not in @job_execution_state
ELSE CONVERT(NVARCHAR, jes.execution_step_id) + N' (' + jes.execution_step_name + N')'
END,
jes.execution_retry_attempt, -- Will be NULL if the job is non-local or is not in @job_execution_state
0, -- last_run_date placeholder (we'll fix it up in step 3.3)
0, -- last_run_time placeholder (we'll fix it up in step 3.3)
5, -- last_run_outcome placeholder (we'll fix it up in step 3.3 - NOTE: We use 5 just in case there are no jobservers for the job)
jes.next_run_date, -- Will be NULL if the job is non-local or is not in @job_execution_state
jes.next_run_time, -- Will be NULL if the job is non-local or is not in @job_execution_state
jes.next_run_schedule_id, -- Will be NULL if the job is non-local or is not in @job_execution_state
0 -- type placeholder (we'll fix it up in step 3.4)
FROM msdb.dbo.sysjobs_view sjv
LEFT OUTER JOIN @job_execution_state jes ON (sjv.job_id = jes.job_id)
LEFT OUTER JOIN msdb.dbo.sysjobsteps sjs ON (sjv.job_id = sjs.job_id)
WHERE ((@subsystem IS NULL) OR (sjs.subsystem = @subsystem))
AND ((@owner_login_name IS NULL)
OR (sjv.owner_sid = dbo.SQLAGENT_SUSER_SID(@owner_login_name)))--force case insensitive comparation for NT users
AND ((@enabled IS NULL) OR (sjv.enabled = @enabled))
AND ((@category_id IS NULL) OR (sjv.category_id = @category_id))
AND ((@execution_status IS NULL) OR ((@execution_status > 0) AND (jes.execution_job_status = @execution_status))
OR ((@execution_status = 0) AND (jes.execution_job_status <> 4) AND (jes.execution_job_status <> 5)))
AND ((@description IS NULL) OR (sjv.description LIKE @description))
AND ((@job_id IS NULL) OR (sjv.job_id = @job_id))
AND ((@schedule_id IS NULL)
OR (EXISTS(SELECT *
FROM sysjobschedules as js
WHERE (sjv.job_id = js.job_id)
AND (js.schedule_id = @schedule_id))))
END
-- Step 3.1: Change the execution status of non-local jobs from 'Idle' to 'Unknown'
UPDATE @filtered_jobs
SET current_execution_status = NULL
WHERE (current_execution_status = 4)
AND (job_id IN (SELECT job_id
FROM msdb.dbo.sysjobservers
WHERE (server_id <> 0)))
-- Step 3.2: Check that if the user asked to see idle jobs that we still have some.
-- If we don't have any then the query should return no rows.
IF (@execution_status = 4) AND
(NOT EXISTS (SELECT *
FROM @filtered_jobs
WHERE (current_execution_status = 4)))
BEGIN
DELETE FROM @filtered_jobs
END
-- Step 3.3: Populate the last run date/time/outcome [this is a little tricky since for
-- multi-server jobs there are multiple last run details in sysjobservers, so
-- we simply choose the most recent].
IF (EXISTS (SELECT *
FROM msdb.dbo.systargetservers))
BEGIN
UPDATE @filtered_jobs
SET last_run_date = sjs.last_run_date,
last_run_time = sjs.last_run_time,
last_run_outcome = sjs.last_run_outcome
FROM @filtered_jobs fj,
msdb.dbo.sysjobservers sjs
WHERE (CONVERT(FLOAT, sjs.last_run_date) * 1000000) + sjs.last_run_time =
(SELECT MAX((CONVERT(FLOAT, last_run_date) * 1000000) + last_run_time)
FROM msdb.dbo.sysjobservers
WHERE (job_id = sjs.job_id))
AND (fj.job_id = sjs.job_id)
END
ELSE
BEGIN
UPDATE @filtered_jobs
SET last_run_date = sjs.last_run_date,
last_run_time = sjs.last_run_time,
last_run_outcome = sjs.last_run_outcome
FROM @filtered_jobs fj,
msdb.dbo.sysjobservers sjs
WHERE (fj.job_id = sjs.job_id)
END
-- Step 3.4 : Set the type of the job to local (1) or multi-server (2)
-- NOTE: If the job has no jobservers then it wil have a type of 0 meaning
-- unknown. This is marginally inconsistent with the behaviour of
-- defaulting the category of a new job to [Uncategorized (Local)], but
-- prevents incompletely defined jobs from erroneously showing up as valid
-- local jobs.
UPDATE @filtered_jobs
SET type = 1 -- LOCAL
FROM @filtered_jobs fj,
msdb.dbo.sysjobservers sjs
WHERE (fj.job_id = sjs.job_id)
AND (server_id = 0)
UPDATE @filtered_jobs
SET type = 2 -- MULTI-SERVER
FROM @filtered_jobs fj,
msdb.dbo.sysjobservers sjs
WHERE (fj.job_id = sjs.job_id)
AND (server_id <> 0)
-- Step 4: Filter on job_type
IF (@job_type IS NOT NULL)
BEGIN
IF (UPPER(@job_type collate SQL_Latin1_General_CP1_CS_AS) = 'LOCAL')
DELETE FROM @filtered_jobs
WHERE (type <> 1) -- IE. Delete all the non-local jobs
IF (UPPER(@job_type collate SQL_Latin1_General_CP1_CS_AS) = 'MULTI-SERVER')
DELETE FROM @filtered_jobs
WHERE (type <> 2) -- IE. Delete all the non-multi-server jobs
END
-- Step 5: Filter on dates
IF (@date_comparator IS NOT NULL)
BEGIN
IF (@date_created IS NOT NULL)
BEGIN
IF (@date_comparator = '=')
DELETE FROM @filtered_jobs WHERE (date_created <> @date_created)
IF (@date_comparator = '>')
DELETE FROM @filtered_jobs WHERE (date_created <= @date_created)
IF (@date_comparator = '<')
DELETE FROM @filtered_jobs WHERE (date_created >= @date_created)
END
IF (@date_last_modified IS NOT NULL)
BEGIN
IF (@date_comparator = '=')
DELETE FROM @filtered_jobs WHERE (date_last_modified <> @date_last_modified)
IF (@date_comparator = '>')
DELETE FROM @filtered_jobs WHERE (date_last_modified <= @date_last_modified)
IF (@date_comparator = '<')
DELETE FROM @filtered_jobs WHERE (date_last_modified >= @date_last_modified)
END
END
-- Return the result set (NOTE: No filtering occurs here)
SELECT sjv.job_id,
originating_server,
sjv.name,
sjv.enabled,
sjv.description,
sjv.start_step_id,
category = ISNULL(sc.name, FORMATMESSAGE(14205)),
owner = dbo.SQLAGENT_SUSER_SNAME(sjv.owner_sid),
sjv.notify_level_eventlog,
sjv.notify_level_email,
sjv.notify_level_netsend,
sjv.notify_level_page,
notify_email_operator = ISNULL(so1.name, FORMATMESSAGE(14205)),
notify_netsend_operator = ISNULL(so2.name, FORMATMESSAGE(14205)),
notify_page_operator = ISNULL(so3.name, FORMATMESSAGE(14205)),
sjv.delete_level,
sjv.date_created,
sjv.date_modified,
sjv.version_number,
fj.last_run_date,
fj.last_run_time,
fj.last_run_outcome,
next_run_date = ISNULL(fj.next_run_date, 0), -- This column will be NULL if the job is non-local
next_run_time = ISNULL(fj.next_run_time, 0), -- This column will be NULL if the job is non-local
next_run_schedule_id = ISNULL(fj.next_run_schedule_id, 0), -- This column will be NULL if the job is non-local
current_execution_status = ISNULL(fj.current_execution_status, 0), -- This column will be NULL if the job is non-local
current_execution_step = ISNULL(fj.current_execution_step, N'0 ' + FORMATMESSAGE(14205)), -- This column will be NULL if the job is non-local
current_retry_attempt = ISNULL(fj.current_retry_attempt, 0), -- This column will be NULL if the job is non-local
has_step = (SELECT COUNT(*)
FROM msdb.dbo.sysjobsteps sjst
WHERE (sjst.job_id = sjv.job_id)),
has_schedule = (SELECT COUNT(*)
FROM msdb.dbo.sysjobschedules sjsch
WHERE (sjsch.job_id = sjv.job_id)),
has_target = (SELECT COUNT(*)
FROM msdb.dbo.sysjobservers sjs
WHERE (sjs.job_id = sjv.job_id)),
type = fj.type
FROM @filtered_jobs fj
LEFT OUTER JOIN msdb.dbo.sysjobs_view sjv ON (fj.job_id = sjv.job_id)
LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjv.notify_email_operator_id = so1.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjv.notify_netsend_operator_id = so2.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjv.notify_page_operator_id = so3.id)
LEFT OUTER JOIN msdb.dbo.syscategories sc ON (sjv.category_id = sc.category_id)
ORDER BY sjv.job_id
END
go
/**************************************************************/
/* SP_HELP_JOB */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_job...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_job')
AND (type = 'P')))
DROP PROCEDURE sp_help_job
go
CREATE PROCEDURE sp_help_job
-- Individual job parameters
@job_id UNIQUEIDENTIFIER = NULL, -- If provided should NOT also provide job_name
@job_name sysname = NULL, -- If provided should NOT also provide job_id
@job_aspect VARCHAR(9) = NULL, -- JOB, STEPS, SCHEDULES, TARGETS or ALL
-- Job set parameters
@job_type VARCHAR(12) = NULL, -- LOCAL or MULTI-SERVER
@owner_login_name sysname = NULL,
@subsystem NVARCHAR(40) = NULL,
@category_name sysname = NULL,
@enabled TINYINT = NULL,
@execution_status INT = NULL, -- 1 = Executing, 2 = Waiting For Thread, 3 = Between Retries, 4 = Idle, 5 = Suspended, 6 = [obsolete], 7 = PerformingCompletionActions
@date_comparator CHAR(1) = NULL, -- >, < or =
@date_created DATETIME = NULL,
@date_last_modified DATETIME = NULL,
@description NVARCHAR(512) = NULL -- We do a LIKE on this so it can include wildcards
AS
BEGIN
DECLARE @retval INT
DECLARE @category_id INT
DECLARE @job_id_as_char VARCHAR(36)
DECLARE @res_valid_range NVARCHAR(200)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters (except @owner_login_name)
SELECT @job_name = LTRIM(RTRIM(@job_name))
SELECT @job_aspect = LTRIM(RTRIM(@job_aspect))
SELECT @job_type = LTRIM(RTRIM(@job_type))
SELECT @subsystem = LTRIM(RTRIM(@subsystem))
SELECT @category_name = LTRIM(RTRIM(@category_name))
SELECT @description = LTRIM(RTRIM(@description))
-- Turn [nullable] empty string parameters into NULLs
IF (@job_name = N'') SELECT @job_name = NULL
IF (@job_aspect = '') SELECT @job_aspect = NULL
IF (@job_type = '') SELECT @job_type = NULL
IF (@owner_login_name = N'') SELECT @owner_login_name = NULL
IF (@subsystem = N'') SELECT @subsystem = NULL
IF (@category_name = N'') SELECT @category_name = NULL
IF (@description = N'') SELECT @description = NULL
IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
BEGIN
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
-- If the user provided a job name or id but no aspect, default to ALL
IF ((@job_name IS NOT NULL) OR (@job_id IS NOT NULL)) AND (@job_aspect IS NULL)
SELECT @job_aspect = 'ALL'
-- The caller must supply EITHER job name (or job id) and aspect OR one-or-more of the set
-- parameters OR no parameters at all
IF (((@job_name IS NOT NULL) OR (@job_id IS NOT NULL))
AND ((@job_aspect IS NULL) OR
(@job_type IS NOT NULL) OR
(@owner_login_name IS NOT NULL) OR
(@subsystem IS NOT NULL) OR
(@category_name IS NOT NULL) OR
(@enabled IS NOT NULL) OR
(@date_comparator IS NOT NULL) OR
(@date_created IS NOT NULL) OR
(@date_last_modified IS NOT NULL)))
OR
((@job_name IS NULL) AND (@job_id IS NULL) AND (@job_aspect IS NOT NULL))
BEGIN
RAISERROR(14280, -1, -1)
RETURN(1) -- Failure
END
IF (@job_id IS NOT NULL)
BEGIN
-- Individual job...
-- Check job aspect
SELECT @job_aspect = UPPER(@job_aspect collate SQL_Latin1_General_CP1_CS_AS)
IF (@job_aspect NOT IN ('JOB', 'STEPS', 'SCHEDULES', 'TARGETS', 'ALL'))
BEGIN
RAISERROR(14266, -1, -1, '@job_aspect', 'JOB, STEPS, SCHEDULES, TARGETS, ALL')
RETURN(1) -- Failure
END
-- Generate results set...
IF (@job_aspect IN ('JOB', 'ALL'))
BEGIN
IF (@job_aspect = 'ALL')
BEGIN
RAISERROR(14213, 0, 1)
PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14213)) / 2)
END
EXECUTE sp_get_composite_job_info @job_id,
@job_type,
@owner_login_name,
@subsystem,
@category_id,
@enabled,
@execution_status,
@date_comparator,
@date_created,
@date_last_modified,
@description
END
IF (@job_aspect IN ('STEPS', 'ALL'))
BEGIN
IF (@job_aspect = 'ALL')
BEGIN
PRINT ''
RAISERROR(14214, 0, 1)
PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14214)) / 2)
END
EXECUTE ('EXECUTE sp_help_jobstep @job_id = ''' + @job_id_as_char + ''', @suffix = 1')
END
IF (@job_aspect IN ('SCHEDULES', 'ALL'))
BEGIN
IF (@job_aspect = 'ALL')
BEGIN
PRINT ''
RAISERROR(14215, 0, 1)
PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14215)) / 2)
END
EXECUTE ('EXECUTE sp_help_jobschedule @job_id = ''' + @job_id_as_char + '''')
END
IF (@job_aspect IN ('TARGETS', 'ALL'))
BEGIN
IF (@job_aspect = 'ALL')
BEGIN
PRINT ''
RAISERROR(14216, 0, 1)
PRINT REPLICATE('=', DATALENGTH(FORMATMESSAGE(14216)) / 2)
END
EXECUTE ('EXECUTE sp_help_jobserver @job_id = ''' + @job_id_as_char + ''', @show_last_run_details = 1')
END
END
ELSE
BEGIN
-- Set of jobs...
-- Check job type
IF (@job_type IS NOT NULL)
BEGIN
SELECT @job_type = UPPER(@job_type collate SQL_Latin1_General_CP1_CS_AS)
IF (@job_type NOT IN ('LOCAL', 'MULTI-SERVER'))
BEGIN
RAISERROR(14266, -1, -1, '@job_type', 'LOCAL, MULTI-SERVER')
RETURN(1) -- Failure
END
END
-- Check owner
IF (@owner_login_name IS NOT NULL)
BEGIN
IF (SUSER_SID(@owner_login_name, 0) IS NULL)--force case insensitive comparation for NT users
BEGIN
RAISERROR(14262, -1, -1, '@owner_login_name', @owner_login_name)
RETURN(1) -- Failure
END
END
-- Check subsystem
IF (@subsystem IS NOT NULL)
BEGIN
EXECUTE @retval = sp_verify_subsystem @subsystem
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- Check job category
IF (@category_name IS NOT NULL)
BEGIN
SELECT @category_id = category_id
FROM msdb.dbo.syscategories
WHERE (category_class = 1) -- Job
AND (name = @category_name)
IF (@category_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@category_name', @category_name)
RETURN(1) -- Failure
END
END
-- Check enabled state
IF (@enabled IS NOT NULL) AND (@enabled NOT IN (0, 1))
BEGIN
RAISERROR(14266, -1, -1, '@enabled', '0, 1')
RETURN(1) -- Failure
END
-- Check current execution status
IF (@execution_status IS NOT NULL)
BEGIN
IF (@execution_status NOT IN (0, 1, 2, 3, 4, 5, 7))
BEGIN
SELECT @res_valid_range = FORMATMESSAGE(14204)
RAISERROR(14266, -1, -1, '@execution_status', @res_valid_range)
RETURN(1) -- Failure
END
END
-- If a date comparator is supplied, we must have either a date-created or date-last-modified
IF ((@date_comparator IS NOT NULL) AND (@date_created IS NOT NULL) AND (@date_last_modified IS NOT NULL)) OR
((@date_comparator IS NULL) AND ((@date_created IS NOT NULL) OR (@date_last_modified IS NOT NULL)))
BEGIN
RAISERROR(14282, -1, -1)
RETURN(1) -- Failure
END
-- Check dates / comparator
IF (@date_comparator IS NOT NULL) AND (@date_comparator NOT IN ('=', '<', '>'))
BEGIN
RAISERROR(14266, -1, -1, '@date_comparator', '=, >, <')
RETURN(1) -- Failure
END
IF (@date_created IS NOT NULL) AND
((@date_created < '19900101') OR (@date_created > '99991231 23:59'))
BEGIN
RAISERROR(14266, -1, -1, '@date_created', '1990-01-01 12:00am .. 9999-12-31 11:59pm')
RETURN(1) -- Failure
END
IF (@date_last_modified IS NOT NULL) AND
((@date_last_modified < '19900101') OR (@date_last_modified > '99991231 23:59'))
BEGIN
RAISERROR(14266, -1, -1, '@date_last_modified', '1990-01-01 12:00am .. 9999-12-31 11:59pm')
RETURN(1) -- Failure
END
-- Generate results set...
EXECUTE sp_get_composite_job_info @job_id,
@job_type,
@owner_login_name,
@subsystem,
@category_id,
@enabled,
@execution_status,
@date_comparator,
@date_created,
@date_last_modified,
@description
END
RETURN(0) -- Success
END
go
CHECKPOINT
go
/**************************************************************/
/* sp_help_jobcount */
/* At least one parameter must be specified */
/* returns a one row/one column recordset with a integer */
/* representing the number of jobs assigned to the */
/* specified schedule */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_jobcount...'
GO
IF (NOT OBJECT_ID(N'dbo.sp_help_jobcount', 'P') IS NULL)
DROP PROCEDURE dbo.sp_help_jobcount
GO
CREATE PROCEDURE sp_help_jobcount
@schedule_name sysname = NULL, -- Specify if @schedule_id is null
@schedule_id INT = NULL -- Specify if @schedule_name is null
AS
BEGIN
SET NOCOUNT ON
DECLARE @retval INT
-- Check that we can uniquely identify the schedule. This only returns a schedule that is visible to this user
EXECUTE @retval = msdb.dbo.sp_verify_schedule_identifiers @name_of_name_parameter = '@schedule_name',
@name_of_id_parameter = '@schedule_id',
@schedule_name = @schedule_name OUTPUT,
@schedule_id = @schedule_id OUTPUT,
@owner_sid = NULL,
@orig_server_id = NULL
IF (@retval <> 0)
RETURN(1) -- Failure
SELECT COUNT(*) AS JobCount
FROM msdb.dbo.sysjobschedules
WHERE (schedule_id = @schedule_id)
RETURN (0) -- 0 means success
END
go
/**************************************************************/
/* sp_help_jobs_in_schedule */
/* At least one parameter must be specified to identify */
/* the schedule. Returns the same information as */
/* sp_help_job. Only jobs in the specified schedule are */
/* in the recordset */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_jobs_in_schedule...'
GO
IF (NOT OBJECT_ID(N'dbo.sp_help_jobs_in_schedule', 'P') IS NULL)
DROP PROCEDURE dbo.sp_help_jobs_in_schedule
GO
CREATE PROCEDURE sp_help_jobs_in_schedule
@schedule_name sysname = NULL, -- Specify if @schedule_id is null
@schedule_id INT = NULL -- Specify if @schedule_name is null
AS
BEGIN
SET NOCOUNT ON
DECLARE @retval INT
-- Check that we can uniquely identify the schedule. This only returns a schedule that is visible to this user
EXECUTE @retval = msdb.dbo.sp_verify_schedule_identifiers @name_of_name_parameter = '@schedule_name',
@name_of_id_parameter = '@schedule_id',
@schedule_name = @schedule_name OUTPUT,
@schedule_id = @schedule_id OUTPUT,
@owner_sid = NULL,
@orig_server_id = NULL
IF (@retval <> 0)
RETURN(1) -- Failure
EXECUTE @retval = msdb.dbo.sp_get_composite_job_info @schedule_id = @schedule_id
IF (@retval <> 0)
RETURN(1) -- Failure
RETURN (0) -- 0 means success
END
go
/**************************************************************/
/* SP_MANAGE_JOBS_BY_LOGIN */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_manage_jobs_by_login...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_manage_jobs_by_login')
AND (type = 'P')))
DROP PROCEDURE sp_manage_jobs_by_login
go
CREATE PROCEDURE sp_manage_jobs_by_login
@action VARCHAR(10), -- DELETE or REASSIGN
@current_owner_login_name sysname,
@new_owner_login_name sysname = NULL
AS
BEGIN
DECLARE @current_sid VARBINARY(85)
DECLARE @new_sid VARBINARY(85)
DECLARE @job_id UNIQUEIDENTIFIER
DECLARE @rows_affected INT
DECLARE @is_sysadmin INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @action = LTRIM(RTRIM(@action))
SELECT @current_owner_login_name = LTRIM(RTRIM(@current_owner_login_name))
SELECT @new_owner_login_name = LTRIM(RTRIM(@new_owner_login_name))
-- Turn [nullable] empty string parameters into NULLs
IF (@new_owner_login_name = N'') SELECT @new_owner_login_name = NULL
-- Only a sysadmin can do this
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Check action
IF (@action NOT IN ('DELETE', 'REASSIGN'))
BEGIN
RAISERROR(14266, -1, -1, '@action', 'DELETE, REASSIGN')
RETURN(1) -- Failure
END
-- Check parameter combinations
IF ((@action = 'DELETE') AND (@new_owner_login_name IS NOT NULL))
RAISERROR(14281, 0, 1)
IF ((@action = 'REASSIGN') AND (@new_owner_login_name IS NULL))
BEGIN
RAISERROR(14237, -1, -1)
RETURN(1) -- Failure
END
-- Check current login
SELECT @current_sid = dbo.SQLAGENT_SUSER_SID(@current_owner_login_name)
IF (@current_sid IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@current_owner_login_name', @current_owner_login_name)
RETURN(1) -- Failure
END
-- Check new login (if supplied)
IF (@new_owner_login_name IS NOT NULL)
BEGIN
SELECT @new_sid = dbo.SQLAGENT_SUSER_SID(@new_owner_login_name)
IF (@new_sid IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@new_owner_login_name', @new_owner_login_name)
RETURN(1) -- Failure
END
END
IF (@action = 'DELETE')
BEGIN
DECLARE jobs_to_delete CURSOR LOCAL
FOR
SELECT job_id
FROM msdb.dbo.sysjobs
WHERE (owner_sid = @current_sid)
OPEN jobs_to_delete
FETCH NEXT FROM jobs_to_delete INTO @job_id
SELECT @rows_affected = 0
WHILE (@@fetch_status = 0)
BEGIN
EXECUTE sp_delete_job @job_id = @job_id
SELECT @rows_affected = @rows_affected + 1
FETCH NEXT FROM jobs_to_delete INTO @job_id
END
DEALLOCATE jobs_to_delete
RAISERROR(14238, 0, 1, @rows_affected)
END
ELSE
IF (@action = 'REASSIGN')
BEGIN
-- Check if the current owner owns any multi-server jobs.
-- If they do, then the new owner must be member of the sysadmin role.
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobs sj,
msdb.dbo.sysjobservers sjs
WHERE (sj.job_id = sjs.job_id)
AND (sj.owner_sid = @current_sid)
AND (sjs.server_id <> 0)) AND @new_sid <> 0xFFFFFFFF) -- speical account allowed for MSX jobs
BEGIN
SELECT @is_sysadmin = 0
EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @new_owner_login_name, @is_sysadmin_member = @is_sysadmin OUTPUT
IF (@is_sysadmin = 0)
BEGIN
RAISERROR(14543, -1, -1, @current_owner_login_name, N'sysadmin')
RETURN(1) -- Failure
END
END
UPDATE msdb.dbo.sysjobs
SET owner_sid = @new_sid
WHERE (owner_sid = @current_sid)
RAISERROR(14239, 0, 1, @@rowcount, @new_owner_login_name)
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_APPLY_JOB_TO_TARGETS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_apply_job_to_targets...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_apply_job_to_targets')
AND (type = 'P')))
DROP PROCEDURE sp_apply_job_to_targets
go
CREATE PROCEDURE sp_apply_job_to_targets
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@target_server_groups NVARCHAR(2048) = NULL, -- A comma-separated list of target server groups
@target_servers NVARCHAR(2048) = NULL, -- An comma-separated list of target servers
@operation VARCHAR(7) = 'APPLY' -- Or 'REMOVE'
AS
BEGIN
DECLARE @retval INT
DECLARE @rows_affected INT
DECLARE @server_name sysname
DECLARE @groups NVARCHAR(2048)
DECLARE @group sysname
DECLARE @servers NVARCHAR(2048)
DECLARE @server sysname
DECLARE @pos_of_comma INT
SET NOCOUNT ON
-- Only a sysadmin can do this
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Remove any leading/trailing spaces from parameters
SELECT @target_server_groups = LTRIM(RTRIM(@target_server_groups))
SELECT @target_servers = UPPER(LTRIM(RTRIM(@target_servers)))
SELECT @operation = LTRIM(RTRIM(@operation))
-- Turn [nullable] empty string parameters into NULLs
IF (@target_server_groups = NULL) SELECT @target_server_groups = NULL
IF (@target_servers = NULL) SELECT @target_servers = NULL
IF (@operation = NULL) SELECT @operation = NULL
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check operation type
IF ((@operation <> 'APPLY') AND (@operation <> 'REMOVE'))
BEGIN
RAISERROR(14266, -1, -1, '@operation', 'APPLY, REMOVE')
RETURN(1) -- Failure
END
-- Check that we have a target server group list and/or a target server list
IF ((@target_server_groups IS NULL) AND (@target_servers IS NULL))
BEGIN
RAISERROR(14283, -1, -1)
RETURN(1) -- Failure
END
DECLARE @temp_groups TABLE (group_name sysname COLLATE database_default NOT NULL)
DECLARE @temp_server_name TABLE (server_name sysname COLLATE database_default NOT NULL)
-- Parse the Target Server comma-separated list (if supplied)
IF (@target_servers IS NOT NULL)
BEGIN
SELECT @servers = @target_servers
SELECT @pos_of_comma = CHARINDEX(N',', @servers)
WHILE (@pos_of_comma <> 0)
BEGIN
SELECT @server = SUBSTRING(@servers, 1, @pos_of_comma - 1)
INSERT INTO @temp_server_name (server_name) VALUES (LTRIM(RTRIM(@server)))
SELECT @servers = RIGHT(@servers, (DATALENGTH(@servers) / 2) - @pos_of_comma)
SELECT @pos_of_comma = CHARINDEX(N',', @servers)
END
INSERT INTO @temp_server_name (server_name) VALUES (LTRIM(RTRIM(@servers)))
END
-- Parse the Target Server Groups comma-separated list
IF (@target_server_groups IS NOT NULL)
BEGIN
SELECT @groups = @target_server_groups
SELECT @pos_of_comma = CHARINDEX(N',', @groups)
WHILE (@pos_of_comma <> 0)
BEGIN
SELECT @group = SUBSTRING(@groups, 1, @pos_of_comma - 1)
INSERT INTO @temp_groups (group_name) VALUES (LTRIM(RTRIM(@group)))
SELECT @groups = RIGHT(@groups, (DATALENGTH(@groups) / 2) - @pos_of_comma)
SELECT @pos_of_comma = CHARINDEX(N',', @groups)
END
INSERT INTO @temp_groups (group_name) VALUES (LTRIM(RTRIM(@groups)))
END
-- Check server groups
SET ROWCOUNT 1 -- We do this so that we catch the FIRST invalid group
SELECT @group = NULL
SELECT @group = group_name
FROM @temp_groups
WHERE group_name NOT IN (SELECT name
FROM msdb.dbo.systargetservergroups)
IF (@group IS NOT NULL)
BEGIN
RAISERROR(14262, -1, -1, '@target_server_groups', @group)
RETURN(1) -- Failure
END
SET ROWCOUNT 0
-- Find the distinct list of servers being targeted
INSERT INTO @temp_server_name (server_name)
SELECT DISTINCT sts.server_name
FROM msdb.dbo.systargetservergroups stsg,
msdb.dbo.systargetservergroupmembers stsgm,
msdb.dbo.systargetservers sts
WHERE (stsg.name IN (SELECT group_name FROM @temp_groups))
AND (stsg.servergroup_id = stsgm.servergroup_id)
AND (stsgm.server_id = sts.server_id)
AND (UPPER(sts.server_name) NOT IN (SELECT server_name
FROM @temp_server_name))
IF (@operation = 'APPLY')
BEGIN
-- Remove those servers to which the job has already been applied
DELETE FROM @temp_server_name
WHERE server_name IN (SELECT sts.server_name
FROM msdb.dbo.sysjobservers sjs,
msdb.dbo.systargetservers sts
WHERE (sjs.job_id = @job_id)
AND (sjs.server_id = sts.server_id))
END
IF (@operation = 'REMOVE')
BEGIN
-- Remove those servers to which the job is not currently applied
DELETE FROM @temp_server_name
WHERE server_name NOT IN (SELECT sts.server_name
FROM msdb.dbo.sysjobservers sjs,
msdb.dbo.systargetservers sts
WHERE (sjs.job_id = @job_id)
AND (sjs.server_id = sts.server_id))
END
SELECT @rows_affected = COUNT(*)
FROM @temp_server_name
SET ROWCOUNT 1
WHILE (EXISTS (SELECT *
FROM @temp_server_name))
BEGIN
SELECT @server_name = server_name
FROM @temp_server_name
IF (@operation = 'APPLY')
EXECUTE sp_add_jobserver @job_id = @job_id, @server_name = @server_name
ELSE
IF (@operation = 'REMOVE')
EXECUTE sp_delete_jobserver @job_id = @job_id, @server_name = @server_name
DELETE FROM @temp_server_name
WHERE (server_name = @server_name)
END
SET ROWCOUNT 0
IF (@operation = 'APPLY')
RAISERROR(14240, 0, 1, @rows_affected)
IF (@operation = 'REMOVE')
RAISERROR(14241, 0, 1, @rows_affected)
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_REMOVE_JOB_FROM_TARGETS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_remove_job_from_targets...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_remove_job_from_targets')
AND (type = 'P')))
DROP PROCEDURE sp_remove_job_from_targets
go
CREATE PROCEDURE sp_remove_job_from_targets
@job_id UNIQUEIDENTIFIER = NULL, -- Must provide either this or job_name
@job_name sysname = NULL, -- Must provide either this or job_id
@target_server_groups NVARCHAR(1024) = NULL, -- A comma-separated list of target server groups
@target_servers NVARCHAR(1024) = NULL -- A comma-separated list of target servers
AS
BEGIN
DECLARE @retval INT
SET NOCOUNT ON
EXECUTE @retval = sp_apply_job_to_targets @job_id,
@job_name,
@target_server_groups,
@target_servers,
'REMOVE'
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_GET_JOB_ALERTS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_get_job_alerts...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_get_job_alerts')
AND (type = 'P')))
DROP PROCEDURE sp_get_job_alerts
go
CREATE PROCEDURE sp_get_job_alerts
@job_id UNIQUEIDENTIFIER = NULL,
@job_name sysname = NULL
AS
BEGIN
DECLARE @retval INT
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
SELECT id,
name,
enabled,
type = CASE ISNULL(performance_condition, '!')
WHEN '!' THEN 1 -- SQL Server event alert
ELSE CASE event_id
WHEN 8 THEN 3 -- WMI event alert
ELSE 2 -- SQL Server performance condition alert
END
END
FROM msdb.dbo.sysalerts
WHERE (job_id = @job_id)
RETURN(0) -- Success
END
go
/**************************************************************/
/* */
/* S U P P O R T P R O C E D U R E S */
/* */
/**************************************************************/
/**************************************************************/
/* SP_START_JOB */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_start_job...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_start_job')
AND (type = 'P')))
DROP PROCEDURE sp_start_job
go
CREATE PROCEDURE sp_start_job
@job_name sysname = NULL,
@job_id UNIQUEIDENTIFIER = NULL,
@error_flag INT = 1, -- Set to 0 to suppress the error from sp_sqlagent_notify if SQLServerAgent is not running
@server_name sysname = NULL, -- The specific target server to start the [multi-server] job on
@step_name sysname = NULL, -- The name of the job step to start execution with [for use with a local job only]
@output_flag INT = 1 -- Set to 0 to suppress the success message
AS
BEGIN
DECLARE @job_id_as_char VARCHAR(36)
DECLARE @retval INT
DECLARE @step_id INT
DECLARE @job_owner_sid VARBINARY(85)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @job_name = LTRIM(RTRIM(@job_name))
SELECT @server_name = UPPER(LTRIM(RTRIM(@server_name)))
SELECT @step_name = LTRIM(RTRIM(@step_name))
-- Turn [nullable] empty string parameters into NULLs
IF (@job_name = N'') SELECT @job_name = NULL
IF (@server_name = N'') SELECT @server_name = NULL
IF (@step_name = N'') SELECT @step_name = NULL
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check permissions beyond what's checked by the sysjobs_view
-- SQLAgentReader role can see all jobs but
-- cannot start/stop jobs they do not own
IF (@job_owner_sid <> SUSER_SID() -- does not own the job
AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) -- is not sysadmin
AND (ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) = 0)) -- is not SQLAgentOperatorRole
BEGIN
RAISERROR(14393, -1, -1);
RETURN(1) -- Failure
END
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)))
BEGIN
SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
RAISERROR(14256, -1, -1, @job_name, @job_id_as_char)
RETURN(1) -- Failure
END
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)))
BEGIN
-- The job is local, so start (run) the job locally
-- Check the step name (if supplied)
IF (@step_name IS NOT NULL)
BEGIN
SELECT @step_id = step_id
FROM msdb.dbo.sysjobsteps
WHERE (step_name = @step_name)
AND (job_id = @job_id)
IF (@step_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@step_name', @step_name)
RETURN(1) -- Failure
END
END
EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type = N'J',
@job_id = @job_id,
@schedule_id = @step_id, -- This is the start step
@action_type = N'S',
@error_flag = @error_flag
IF ((@retval = 0) AND (@output_flag = 1))
RAISERROR(14243, 0, 1, @job_name)
END
ELSE
BEGIN
-- The job is a multi-server job
-- Only sysadmin can start multi-server job
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(14397, -1, -1);
RETURN(1) -- Failure
END
-- Check target server name (if any)
IF (@server_name IS NOT NULL)
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = @server_name)))
BEGIN
RAISERROR(14262, -1, -1, '@server_name', @server_name)
RETURN(1) -- Failure
END
END
-- Re-post the job if it's an auto-delete job
IF ((SELECT delete_level
FROM msdb.dbo.sysjobs
WHERE (job_id = @job_id)) <> 0)
EXECUTE @retval = msdb.dbo.sp_post_msx_operation 'INSERT', 'JOB', @job_id, @server_name
-- Post start instruction(s)
EXECUTE @retval = msdb.dbo.sp_post_msx_operation 'START', 'JOB', @job_id, @server_name
END
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_STOP_JOB */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_stop_job...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_stop_job')
AND (type = 'P')))
DROP PROCEDURE sp_stop_job
go
CREATE PROCEDURE sp_stop_job
@job_name sysname = NULL,
@job_id UNIQUEIDENTIFIER = NULL,
@originating_server sysname = NULL, -- So that we can stop ALL jobs that came from the given server
@server_name sysname = NULL -- The specific target server to stop the [multi-server] job on
AS
BEGIN
DECLARE @job_id_as_char VARCHAR(36)
DECLARE @retval INT
DECLARE @num_parameters INT
DECLARE @job_owner_sid VARBINARY(85)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @job_name = LTRIM(RTRIM(@job_name))
SELECT @originating_server = UPPER(LTRIM(RTRIM(@originating_server)))
SELECT @server_name = UPPER(LTRIM(RTRIM(@server_name)))
-- Turn [nullable] empty string parameters into NULLs
IF (@job_name = N'') SELECT @job_name = NULL
IF (@originating_server = N'') SELECT @originating_server = NULL
IF (@server_name = N'') SELECT @server_name = NULL
-- We must have EITHER a job id OR a job name OR an originating server
SELECT @num_parameters = 0
IF (@job_id IS NOT NULL)
SELECT @num_parameters = @num_parameters + 1
IF (@job_name IS NOT NULL)
SELECT @num_parameters = @num_parameters + 1
IF (@originating_server IS NOT NULL)
SELECT @num_parameters = @num_parameters + 1
IF (@num_parameters <> 1)
BEGIN
RAISERROR(14232, -1, -1)
RETURN(1) -- Failure
END
IF (@originating_server IS NOT NULL)
BEGIN
-- Stop (cancel) ALL local jobs that originated from the specified server
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobs_view
WHERE (originating_server = @originating_server)))
BEGIN
RAISERROR(14268, -1, -1, @originating_server)
RETURN(1) -- Failure
END
-- Check permissions beyond what's checked by the sysjobs_view
-- SQLAgentReader role that can see all jobs but
-- cannot start/stop jobs they do not own
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) -- is not sysadmin
AND (ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) = 0)) -- is not SQLAgentOperatorRole
BEGIN
RAISERROR(14393, -1, -1);
RETURN(1) -- Failure
END
DECLARE @total_counter INT
DECLARE @success_counter INT
DECLARE stop_jobs CURSOR LOCAL
FOR
SELECT job_id
FROM msdb.dbo.sysjobs_view
WHERE (originating_server = @originating_server)
SELECT @total_counter = 0, @success_counter = 0
OPEN stop_jobs
FETCH NEXT FROM stop_jobs INTO @job_id
WHILE (@@fetch_status = 0)
BEGIN
SELECT @total_counter + @total_counter + 1
EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type = N'J',
@job_id = @job_id,
@action_type = N'C'
IF (@retval = 0)
SELECT @success_counter = @success_counter + 1
FETCH NEXT FROM stop_jobs INTO @job_id
END
RAISERROR(14253, 0, 1, @success_counter, @total_counter)
DEALLOCATE stop_jobs
RETURN(0) -- 0 means success
END
ELSE
BEGIN
-- Stop ONLY the specified job
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT,
@owner_sid = @job_owner_sid OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)))
BEGIN
SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
RAISERROR(14257, -1, -1, @job_name, @job_id_as_char)
RETURN(1) -- Failure
END
-- Check permissions beyond what's checked by the sysjobs_view
-- SQLAgentReader role that can see all jobs but
-- cannot start/stop jobs they do not own
IF (@job_owner_sid <> SUSER_SID() -- does not own the job
AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) -- is not sysadmin
AND (ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) = 0)) -- is not SQLAgentOperatorRole
BEGIN
RAISERROR(14393, -1, -1);
RETURN(1) -- Failure
END
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @job_id)
AND (server_id = 0)))
BEGIN
-- The job is local, so stop (cancel) the job locally
EXECUTE @retval = msdb.dbo.sp_sqlagent_notify @op_type = N'J',
@job_id = @job_id,
@action_type = N'C'
IF (@retval = 0)
RAISERROR(14254, 0, 1, @job_name)
END
ELSE
BEGIN
-- The job is a multi-server job
-- Only sysadmin can stop multi-server job
IF (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1)
BEGIN
RAISERROR(14397, -1, -1);
RETURN(1) -- Failure
END
-- Check target server name (if any)
IF (@server_name IS NOT NULL)
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = @server_name)))
BEGIN
RAISERROR(14262, -1, -1, '@server_name', @server_name)
RETURN(1) -- Failure
END
END
-- Post the stop instruction(s)
EXECUTE @retval = sp_post_msx_operation 'STOP', 'JOB', @job_id, @server_name
END
RETURN(@retval) -- 0 means success
END
END
go
/**************************************************************/
/* SP_CYCLE_AGENT_ERRORLOG */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_cycle_agent_errorlog...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_cycle_agent_errorlog')
AND (type = 'P')))
DROP PROCEDURE sp_cycle_agent_errorlog
go
CREATE PROCEDURE sp_cycle_agent_errorlog
AS
BEGIN
exec sp_sqlagent_notify N'L'
END
go
/**************************************************************/
/* SP_GET_CHUNKED_JOBSTEP_PARAMS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_get_chunked_jobstep_params...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_get_chunked_jobstep_params')
AND (type = 'P')))
DROP PROCEDURE sp_get_chunked_jobstep_params
go
CREATE PROCEDURE sp_get_chunked_jobstep_params
@job_name sysname,
@step_id INT = 1
AS
BEGIN
DECLARE @job_id UNIQUEIDENTIFIER
DECLARE @step_id_as_char VARCHAR(10)
DECLARE @retval INT
SET NOCOUNT ON
-- Check that the job exists
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check that the step exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND (step_id = @step_id)))
BEGIN
SELECT @step_id_as_char = CONVERT(VARCHAR(10), @step_id)
RAISERROR(14262, -1, -1, '@step_id', @step_id_as_char)
RETURN(1) -- Failure
END
-- Return the sysjobsteps.additional_parameters
SELECT additional_parameters
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND (step_id = @step_id)
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_CHECK_FOR_OWNED_JOBS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_check_for_owned_jobs...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_check_for_owned_jobs')
AND (type = 'P')))
DROP PROCEDURE sp_check_for_owned_jobs
go
CREATE PROCEDURE sp_check_for_owned_jobs
@login_name sysname,
@table_name sysname
AS
BEGIN
SET NOCOUNT ON
-- This procedure is called by sp_droplogin to check if the login being dropped
-- still owns jobs. The return value (the number of jobs owned) is passed back
-- via the supplied table name [this cumbersome approach is necessary because
-- sp_check_for_owned_jobs is invoked via an EXEC() and because we always want
-- sp_droplogin to work, even if msdb and/or sysjobs does not exist].
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysjobs')
AND (type = 'U')))
BEGIN
DECLARE @sql NVARCHAR(1024)
SET @sql = N'INSERT INTO ' + QUOTENAME(@table_name, N'[') + N' SELECT COUNT(*) FROM msdb.dbo.sysjobs WHERE (owner_sid = SUSER_SID(N' + QUOTENAME(@login_name, '''') + ', 0))' --force case insensitive comparation for NT users
EXEC sp_executesql @statement = @sql
END
END
go
/**************************************************************/
/* SP_CHECK_FOR_OWNED_JOBSTEPS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_check_for_owned_jobsteps...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_check_for_owned_jobsteps')
AND (type = 'P')))
DROP PROCEDURE sp_check_for_owned_jobsteps
go
CREATE PROCEDURE sp_check_for_owned_jobsteps
@login_name sysname = NULL, -- Supply this OR the database_X parameters, but not both
@database_name sysname = NULL,
@database_user_name sysname = NULL
AS
BEGIN
DECLARE @db_name NVARCHAR(128)
DECLARE @delimited_db_name NVARCHAR(258)
DECLARE @escaped_db_name NVARCHAR(256) -- double sysname
DECLARE @escaped_login_name NVARCHAR(256) -- double sysname
SET NOCOUNT ON
CREATE TABLE #work_table
(
database_name sysname COLLATE database_default,
database_user_name sysname COLLATE database_default
)
IF ((@login_name IS NOT NULL) AND (@database_name IS NULL) AND (@database_user_name IS NULL))
BEGIN
IF (SUSER_SID(@login_name, 0) IS NULL)--force case insensitive comparation for NT users
BEGIN
DROP TABLE #work_table
RAISERROR(14262, -1, -1, '@login_name', @login_name)
RETURN(1) -- Failure
END
DECLARE all_databases CURSOR LOCAL
FOR
SELECT name
FROM master.dbo.sysdatabases
OPEN all_databases
FETCH NEXT FROM all_databases INTO @db_name
-- Double up any single quotes in @login_name
SELECT @escaped_login_name = REPLACE(@login_name, N'''', N'''''')
WHILE (@@fetch_status = 0)
BEGIN
SELECT @delimited_db_name = QUOTENAME(@db_name, N'[')
SELECT @escaped_db_name = REPLACE(@db_name, '''', '''''')
EXECUTE(N'INSERT INTO #work_table
SELECT N''' + @escaped_db_name + N''', name
FROM ' + @delimited_db_name + N'.dbo.sysusers
WHERE (sid = SUSER_SID(N''' + @escaped_login_name + N''', 0))')--force case insensitive comparation for NT users
FETCH NEXT FROM all_databases INTO @db_name
END
DEALLOCATE all_databases
-- If the login is an NT login, check for steps run as the login directly (as is the case with transient NT logins)
IF (@login_name LIKE '%\%')
BEGIN
INSERT INTO #work_table
SELECT database_name, database_user_name
FROM msdb.dbo.sysjobsteps
WHERE (database_user_name = @login_name)
END
END
IF ((@login_name IS NULL) AND (@database_name IS NOT NULL) AND (@database_user_name IS NOT NULL))
BEGIN
INSERT INTO #work_table
SELECT @database_name, @database_user_name
END
IF (EXISTS (SELECT *
FROM #work_table wt,
msdb.dbo.sysjobsteps sjs
WHERE (wt.database_name = sjs.database_name)
AND (wt.database_user_name = sjs.database_user_name)))
BEGIN
SELECT sjv.job_id,
sjv.name,
sjs.step_id,
sjs.step_name
FROM #work_table wt,
msdb.dbo.sysjobsteps sjs,
msdb.dbo.sysjobs_view sjv
WHERE (wt.database_name = sjs.database_name)
AND (wt.database_user_name = sjs.database_user_name)
AND (sjv.job_id = sjs.job_id)
ORDER BY sjs.job_id
END
DROP TABLE #work_table
RETURN(0) -- 0 means success
END
go
/**************************************************************/
/* SP_SQLAGENT_REFRESH_JOB */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sqlagent_refresh_job...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_sqlagent_refresh_job')
AND (type = 'P')))
DROP PROCEDURE sp_sqlagent_refresh_job
go
CREATE PROCEDURE sp_sqlagent_refresh_job
@job_id UNIQUEIDENTIFIER = NULL,
@server_name sysname = NULL -- This parameter allows a TSX to use this SP when updating a job
AS
BEGIN
DECLARE @server_id INT
SET NOCOUNT ON
IF (@server_name IS NULL) OR (UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = '(LOCAL)')
SELECT @server_name = CONVERT(sysname, SERVERPROPERTY('ServerName'))
SELECT @server_name = UPPER(@server_name)
SELECT @server_id = server_id
FROM msdb.dbo.systargetservers_view
WHERE (UPPER(server_name) = ISNULL(@server_name, UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))))
SELECT @server_id = ISNULL(@server_id, 0)
SELECT sjv.job_id,
sjv.name,
sjv.enabled,
sjv.start_step_id,
owner = dbo.SQLAGENT_SUSER_SNAME(sjv.owner_sid),
sjv.notify_level_eventlog,
sjv.notify_level_email,
sjv.notify_level_netsend,
sjv.notify_level_page,
sjv.notify_email_operator_id,
sjv.notify_netsend_operator_id,
sjv.notify_page_operator_id,
sjv.delete_level,
has_step = (SELECT COUNT(*)
FROM msdb.dbo.sysjobsteps sjst
WHERE (sjst.job_id = sjv.job_id)),
sjv.version_number,
last_run_date = ISNULL(sjs.last_run_date, 0),
last_run_time = ISNULL(sjs.last_run_time, 0),
sjv.originating_server,
sjv.description,
agent_account = CASE sjv.owner_sid
WHEN 0xFFFFFFFF THEN 1
ELSE 0
END
FROM msdb.dbo.sysjobservers sjs,
msdb.dbo.sysjobs_view sjv
WHERE ((@job_id IS NULL) OR (@job_id = sjv.job_id))
AND (sjv.job_id = sjs.job_id)
AND (sjs.server_id = @server_id)
ORDER BY sjv.job_id
OPTION (FORCE ORDER)
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_JOBHISTORY_ROW_LIMITER */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_jobhistory_row_limiter...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_jobhistory_row_limiter')
AND (type = 'P')))
DROP PROCEDURE dbo.sp_jobhistory_row_limiter
go
CREATE PROCEDURE sp_jobhistory_row_limiter
@job_id UNIQUEIDENTIFIER
AS
BEGIN
DECLARE @max_total_rows INT -- This value comes from the registry (MaxJobHistoryTableRows)
DECLARE @max_rows_per_job INT -- This value comes from the registry (MaxJobHistoryRows)
DECLARE @rows_to_delete INT
DECLARE @current_rows INT
DECLARE @current_rows_per_job INT
SET NOCOUNT ON
-- Get max-job-history-rows from the registry
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'JobHistoryMaxRows',
@max_total_rows OUTPUT,
N'no_output'
-- Check if we are limiting sysjobhistory rows
IF (ISNULL(@max_total_rows, -1) = -1)
RETURN(0)
-- Check that max_total_rows is more than 1
IF (ISNULL(@max_total_rows, 0) < 2)
BEGIN
-- It isn't, so set the default to 1000 rows
SELECT @max_total_rows = 1000
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'JobHistoryMaxRows',
N'REG_DWORD',
@max_total_rows
END
-- Get the per-job maximum number of rows to keep
SELECT @max_rows_per_job = 0
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'JobHistoryMaxRowsPerJob',
@max_rows_per_job OUTPUT,
N'no_output'
-- Check that max_rows_per_job is <= max_total_rows
IF ((@max_rows_per_job > @max_total_rows) OR (@max_rows_per_job < 1))
BEGIN
-- It isn't, so default the rows_per_job to max_total_rows
SELECT @max_rows_per_job = @max_total_rows
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'JobHistoryMaxRowsPerJob',
N'REG_DWORD',
@max_rows_per_job
END
BEGIN TRANSACTION
SELECT @current_rows_per_job = COUNT(*)
FROM msdb.dbo.sysjobhistory with (TABLOCKX)
WHERE (job_id = @job_id)
-- Delete the oldest history row(s) for the job being inserted if the new row has
-- pushed us over the per-job row limit (MaxJobHistoryRows)
SELECT @rows_to_delete = @current_rows_per_job - @max_rows_per_job
IF (@rows_to_delete > 0)
BEGIN
WITH RowsToDelete AS (
SELECT TOP (@rows_to_delete) *
FROM msdb.dbo.sysjobhistory
WHERE (job_id = @job_id)
ORDER BY instance_id
)
DELETE FROM RowsToDelete;
END
-- Delete the oldest history row(s) if inserting the new row has pushed us over the
-- global MaxJobHistoryTableRows limit.
SELECT @current_rows = COUNT(*)
FROM msdb.dbo.sysjobhistory
SELECT @rows_to_delete = @current_rows - @max_total_rows
IF (@rows_to_delete > 0)
BEGIN
WITH RowsToDelete AS (
SELECT TOP (@rows_to_delete) *
FROM msdb.dbo.sysjobhistory
ORDER BY instance_id
)
DELETE FROM RowsToDelete;
END
IF (@@trancount > 0)
COMMIT TRANSACTION
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_SQLAGENT_LOG_JOBHISTORY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sqlagent_log_jobhistory...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_sqlagent_log_jobhistory')
AND (type = 'P')))
DROP PROCEDURE sp_sqlagent_log_jobhistory
go
CREATE PROCEDURE sp_sqlagent_log_jobhistory
@job_id UNIQUEIDENTIFIER,
@step_id INT,
@sql_message_id INT = 0,
@sql_severity INT = 0,
@message NVARCHAR(4000) = NULL,
@run_status INT, -- SQLAGENT_EXEC_X code
@run_date INT,
@run_time INT,
@run_duration INT,
@operator_id_emailed INT = 0,
@operator_id_netsent INT = 0,
@operator_id_paged INT = 0,
@retries_attempted INT,
@server sysname = NULL,
@session_id INT = 0
AS
BEGIN
DECLARE @retval INT
DECLARE @operator_id_as_char VARCHAR(10)
DECLARE @step_name sysname
DECLARE @error_severity INT
SET NOCOUNT ON
IF (@server IS NULL) OR (UPPER(@server collate SQL_Latin1_General_CP1_CS_AS) = '(LOCAL)')
SELECT @server = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName')))
-- Check authority (only SQLServerAgent can add a history entry for a job)
EXECUTE @retval = sp_verify_jobproc_caller @job_id = @job_id, @program_name = N'SQLAgent%'
IF (@retval <> 0)
RETURN(@retval)
-- NOTE: We raise all errors as informational (sev 0) to prevent SQLServerAgent from caching
-- the operation (if it fails) since if the operation will never run successfully we
-- don't want it to hang around in the operation cache.
SELECT @error_severity = 0
-- Check job_id
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobs_view
WHERE (job_id = @job_id)))
BEGIN
DECLARE @job_id_as_char VARCHAR(36)
SELECT @job_id_as_char = CONVERT(VARCHAR(36), @job_id)
RAISERROR(14262, @error_severity, -1, 'Job', @job_id_as_char)
RETURN(1) -- Failure
END
-- Check step id
IF (@step_id <> 0) -- 0 means 'for the whole job'
BEGIN
SELECT @step_name = step_name
FROM msdb.dbo.sysjobsteps
WHERE (job_id = @job_id)
AND (step_id = @step_id)
IF (@step_name IS NULL)
BEGIN
DECLARE @step_id_as_char VARCHAR(10)
SELECT @step_id_as_char = CONVERT(VARCHAR, @step_id)
RAISERROR(14262, @error_severity, -1, '@step_id', @step_id_as_char)
RETURN(1) -- Failure
END
END
ELSE
SELECT @step_name = FORMATMESSAGE(14570)
-- Check run_status
IF (@run_status NOT IN (0, 1, 2, 3, 4, 5)) -- SQLAGENT_EXEC_X code
BEGIN
RAISERROR(14266, @error_severity, -1, '@run_status', '0, 1, 2, 3, 4, 5')
RETURN(1) -- Failure
END
-- Check run_date
EXECUTE @retval = sp_verify_job_date @run_date, '@run_date', 10
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check run_time
EXECUTE @retval = sp_verify_job_time @run_time, '@run_time', 10
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check operator_id_emailed
IF (@operator_id_emailed <> 0)
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysoperators
WHERE (id = @operator_id_emailed)))
BEGIN
SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_emailed)
RAISERROR(14262, @error_severity, -1, '@operator_id_emailed', @operator_id_as_char)
RETURN(1) -- Failure
END
END
-- Check operator_id_netsent
IF (@operator_id_netsent <> 0)
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysoperators
WHERE (id = @operator_id_netsent)))
BEGIN
SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_netsent)
RAISERROR(14262, @error_severity, -1, '@operator_id_netsent', @operator_id_as_char)
RETURN(1) -- Failure
END
END
-- Check operator_id_paged
IF (@operator_id_paged <> 0)
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysoperators
WHERE (id = @operator_id_paged)))
BEGIN
SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id_paged)
RAISERROR(14262, @error_severity, -1, '@operator_id_paged', @operator_id_as_char)
RETURN(1) -- Failure
END
END
-- Insert the history row
INSERT INTO msdb.dbo.sysjobhistory
(job_id,
step_id,
step_name,
sql_message_id,
sql_severity,
message,
run_status,
run_date,
run_time,
run_duration,
operator_id_emailed,
operator_id_netsent,
operator_id_paged,
retries_attempted,
server)
VALUES (@job_id,
@step_id,
@step_name,
@sql_message_id,
@sql_severity,
@message,
@run_status,
@run_date,
@run_time,
@run_duration,
@operator_id_emailed,
@operator_id_netsent,
@operator_id_paged,
@retries_attempted,
@server)
-- Update sysjobactivity table
IF (@step_id = 0) --only update for job, not for each step
BEGIN
UPDATE msdb.dbo.sysjobactivity
SET stop_execution_date = DATEADD(ms, -DATEPART(ms, GetDate()), GetDate()),
job_history_id = SCOPE_IDENTITY()
WHERE
session_id = @session_id AND job_id = @job_id
END
-- Special handling of replication jobs
DECLARE @job_name sysname
DECLARE @category_id int
SELECT @job_name = name, @category_id = category_id from msdb.dbo.sysjobs
WHERE job_id = @job_id
-- If replicatio agents (snapshot, logreader, distribution, merge, and queuereader
-- and the step has been canceled and if we are at the distributor.
IF @category_id in (10,13,14,15,19) and @run_status = 3 and
object_id('MSdistributiondbs') is not null
BEGIN
-- Get the database
DECLARE @database sysname
SELECT @database = database_name from sysjobsteps where job_id = @job_id and
lower(subsystem) in (N'distribution', N'logreader','snapshot',N'merge',
N'queuereader')
-- If the database is a distribution database
IF EXISTS (select * from MSdistributiondbs where name = @database)
BEGIN
DECLARE @proc nvarchar(500)
SELECT @proc = quotename(@database) + N'.dbo.sp_MSlog_agent_cancel'
EXEC @proc @job_id = @job_id, @category_id = @category_id,
@message = @message
END
END
-- Delete any history rows that are over the registry-defined limits
IF (@step_id = 0) --only check once per job execution.
BEGIN
EXECUTE msdb.dbo.sp_jobhistory_row_limiter @job_id
END
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_SQLAGENT_CHECK_MSX_VERSION */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sqlagent_check_msx_version...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_sqlagent_check_msx_version')
AND (type = 'P')))
DROP PROCEDURE sp_sqlagent_check_msx_version
go
CREATE PROCEDURE sp_sqlagent_check_msx_version
@required_microsoft_version INT = NULL
AS
BEGIN
SET NOCOUNT ON
DECLARE @msx_version NVARCHAR(16)
DECLARE @required_msx_version NVARCHAR(16)
IF (@required_microsoft_version IS NULL)
SELECT @required_microsoft_version = 0x07000252 -- 7.0.594
IF (@@microsoftversion < @required_microsoft_version)
BEGIN
SELECT @msx_version = CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), @@microsoftversion / 0x1000000 ) ) )
+ N'.'
+ CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), CONVERT( BINARY(2), ((@@microsoftversion / 0x10000) % 0x100) ) ) ) )
+ N'.'
+ CONVERT( NVARCHAR(4), @@microsoftversion % 0x10000 )
SELECT @required_msx_version = CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), @required_microsoft_version / 0x1000000 ) ) )
+ N'.'
+ CONVERT( NVARCHAR(2), CONVERT( INT, CONVERT( BINARY(1), CONVERT( BINARY(2), ((@required_microsoft_version / 0x10000) % 0x100) ) ) ) )
+ N'.'
+ CONVERT( NVARCHAR(4), @required_microsoft_version % 0x10000 )
RAISERROR(14541, -1, -1, @msx_version, @required_msx_version)
RETURN(1) -- Failure
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_SQLAGENT_PROBE_MSX */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sqlagent_probe_msx...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_sqlagent_probe_msx')
AND (type = 'P')))
DROP PROCEDURE sp_sqlagent_probe_msx
go
CREATE PROCEDURE sp_sqlagent_probe_msx
@server_name sysname, -- The name of the target server probing the MSX
@local_time NVARCHAR(100), -- The local time at the target server in the format YYYY/MM/DD HH:MM:SS
@poll_interval INT, -- The frequency (in seconds) with which the target polls the MSX
@time_zone_adjustment INT = NULL -- The offset from GMT in minutes (may be NULL if unknown)
AS
BEGIN
DECLARE @bad_enlistment BIT
DECLARE @blocking_instructions INT
DECLARE @pending_instructions INT
SET NOCOUNT ON
SELECT @server_name = UPPER(@server_name)
SELECT @bad_enlistment = 0, @blocking_instructions = 0, @pending_instructions = 0
UPDATE msdb.dbo.systargetservers
SET last_poll_date = GETDATE(),
local_time_at_last_poll = CONVERT(DATETIME, @local_time, 111),
poll_interval = @poll_interval,
time_zone_adjustment = ISNULL(@time_zone_adjustment, time_zone_adjustment)
WHERE (UPPER(server_name) = @server_name)
-- If the systargetservers entry is missing (and no DEFECT instruction has been posted)
-- then the enlistment is bad
IF (NOT EXISTS (SELECT 1
FROM msdb.dbo.systargetservers
WHERE (UPPER(server_name) = @server_name))) AND
(NOT EXISTS (SELECT 1
FROM msdb.dbo.sysdownloadlist
WHERE (target_server = @server_name)
AND (operation_code = 7)
AND (object_type = 2)))
SELECT @bad_enlistment = 1
SELECT @blocking_instructions = COUNT(*)
FROM msdb.dbo.sysdownloadlist
WHERE (target_server = @server_name)
AND (error_message IS NOT NULL)
SELECT @pending_instructions = COUNT(*)
FROM msdb.dbo.sysdownloadlist
WHERE (target_server = @server_name)
AND (error_message IS NULL)
AND (status = 0)
SELECT @bad_enlistment, @blocking_instructions, @pending_instructions
END
go
/**************************************************************/
/* SP_SET_LOCAL_TIME */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_set_local_time...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_set_local_time')
AND (type = 'P')))
DROP PROCEDURE sp_set_local_time
go
CREATE PROCEDURE sp_set_local_time
@server_name sysname = NULL,
@adjustment_in_minutes INT = 0 -- Only needed for Win9x
AS
BEGIN
DECLARE @ret INT
DECLARE @local_time INT
DECLARE @local_date INT
DECLARE @current_datetime DATETIME
DECLARE @local_time_sz VARCHAR(30)
DECLARE @cmd NVARCHAR(200)
DECLARE @date_format NVARCHAR(64)
DECLARE @year_sz NVARCHAR(16)
DECLARE @month_sz NVARCHAR(16)
DECLARE @day_sz NVARCHAR(16)
-- Synchronize the clock with the remote server (if supplied)
-- NOTE: NT takes timezones into account, whereas Win9x does not
IF (@server_name IS NOT NULL)
BEGIN
SELECT @cmd = N'net time \\' + @server_name + N' /set /y'
EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output
IF (@ret <> 0)
RETURN(1) -- Failure
END
-- Since NET TIME on Win9x does not take time zones into account we need to manually adjust
-- for this using @adjustment_in_minutes which will be the difference between the MSX GMT
-- offset and the target server GMT offset
IF ((PLATFORM() & 0x2) = 0x2) -- Win9x
BEGIN
-- Get the date format from the registry (so that we can construct our DATE command-line command)
EXECUTE master.dbo.xp_regread N'HKEY_CURRENT_USER',
N'Control Panel\International',
N'sShortDate',
@date_format OUTPUT,
N'no_output'
SELECT @date_format = LOWER(@date_format)
IF (@adjustment_in_minutes <> 0)
BEGIN
-- Wait for SQLServer to re-cache the OS time
WAITFOR DELAY '00:01:00'
SELECT @current_datetime = DATEADD(mi, @adjustment_in_minutes, GETDATE())
SELECT @local_time_sz = SUBSTRING(CONVERT(VARCHAR, @current_datetime, 8), 1, 5)
SELECT @local_time = CONVERT(INT, LTRIM(SUBSTRING(@local_time_sz, 1, PATINDEX('%:%', @local_time_sz) - 1) + SUBSTRING(@local_time_sz, PATINDEX('%:%', @local_time_sz) + 1, 2)))
SELECT @local_date = CONVERT(INT, CONVERT(VARCHAR, @current_datetime, 112))
-- Set the date
SELECT @year_sz = CONVERT(NVARCHAR, @local_date / 10000)
SELECT @month_sz = CONVERT(NVARCHAR, (@local_date % 10000) / 100)
SELECT @day_sz = CONVERT(NVARCHAR, @local_date % 100)
IF (@date_format LIKE N'y%m%d')
SELECT @cmd = N'DATE ' + @year_sz + N'-' + @month_sz + N'-' + @day_sz
IF (@date_format LIKE N'y%d%m')
SELECT @cmd = N'DATE ' + @year_sz + N'-' + @day_sz + N'-' + @month_sz
IF (@date_format LIKE N'm%d%y')
SELECT @cmd = N'DATE ' + @month_sz + N'-' + @day_sz + N'-' + @year_sz
IF (@date_format LIKE N'd%m%y')
SELECT @cmd = N'DATE ' + @day_sz + N'-' + @month_sz + N'-' + @year_sz
EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output
IF (@ret <> 0)
RETURN 1 -- Failure
-- Set the time (NOTE: We can't set the millisecond part of the time, so we may be up to .999 sec off)
SELECT @cmd = N'TIME ' + CONVERT(NVARCHAR, @local_time / 100) + N':' + CONVERT(NVARCHAR, @local_time % 100) + ':' + CONVERT(NVARCHAR(2), DATEPART(SS, GETDATE()))
EXECUTE @ret = master.dbo.xp_cmdshell @cmd, no_output
IF (@ret <> 0)
RETURN 1 -- Failure
END
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_MULTI_SERVER_JOB_SUMMARY [used by SEM only] */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_multi_server_job_summary...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_multi_server_job_summary')
AND (type = 'P')))
DROP PROCEDURE sp_multi_server_job_summary
go
CREATE PROCEDURE sp_multi_server_job_summary
@job_id UNIQUEIDENTIFIER = NULL,
@job_name sysname = NULL
AS
BEGIN
DECLARE @retval INT
SET NOCOUNT ON
IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
BEGIN
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
-- NOTE: We join with syscategories - not sysjobservers - since we want to include jobs
-- which are of type multi-server but which don't currently have any servers
SELECT 'job_id' = sj.job_id,
'job_name' = sj.name,
'enabled' = sj.enabled,
'category_name' = sc.name,
'target_servers' = (SELECT COUNT(*)
FROM msdb.dbo.sysjobservers sjs
WHERE (sjs.job_id = sj.job_id)),
'pending_download_instructions' = (SELECT COUNT(*)
FROM msdb.dbo.sysdownloadlist sdl
WHERE (sdl.object_id = sj.job_id)
AND (status = 0)),
'download_errors' = (SELECT COUNT(*)
FROM msdb.dbo.sysdownloadlist sdl
WHERE (sdl.object_id = sj.job_id)
AND (sdl.error_message IS NOT NULL)),
'execution_failures' = (SELECT COUNT(*)
FROM msdb.dbo.sysjobservers sjs
WHERE (sjs.job_id = sj.job_id)
AND (sjs.last_run_date <> 0)
AND (sjs.last_run_outcome <> 1)) -- 1 is success
FROM msdb.dbo.sysjobs sj,
msdb.dbo.syscategories sc
WHERE (sj.category_id = sc.category_id)
AND (sc.category_class = 1) -- JOB
AND (sc.category_type = 2) -- Multi-Server
AND ((@job_id IS NULL) OR (sj.job_id = @job_id))
AND ((@job_name IS NULL) OR (sj.name = @job_name))
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_TARGET_SERVER_SUMMARY [used by SEM only] */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_target_server_summary...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_target_server_summary')
AND (type = 'P')))
DROP PROCEDURE sp_target_server_summary
go
CREATE PROCEDURE sp_target_server_summary
@target_server sysname = NULL
AS
BEGIN
SET NOCOUNT ON
SELECT server_id,
server_name,
'local_time' = DATEADD(SS, DATEDIFF(SS, last_poll_date, GETDATE()), local_time_at_last_poll),
last_poll_date,
'unread_instructions' = (SELECT COUNT(*)
FROM msdb.dbo.sysdownloadlist sdl
WHERE (UPPER(sdl.target_server) = UPPER(sts.server_name))
AND (sdl.status = 0)),
'blocked' = (SELECT COUNT(*)
FROM msdb.dbo.sysdownloadlist sdl
WHERE (UPPER(sdl.target_server) = UPPER(sts.server_name))
AND (sdl.error_message IS NOT NULL)),
poll_interval
FROM msdb.dbo.systargetservers sts
WHERE ((@target_server IS NULL) OR (UPPER(@target_server) = UPPER(sts.server_name)))
END
go
CHECKPOINT
go
/**************************************************************/
/* */
/* 6 . X P R O C E D U R E S */
/* */
/* These procedures are provided for backwards compatability */
/* with 6.x scripts and 6.x replication. The re-implemented */
/* procedures are as follows: */
/* */
/* - sp_uniquetaskname (SQLDMO) */
/* - systasks_view (INSTDIST.SQL) */
/* - sp_addtask (INSTREPL.SQL, INSTDIST.SQL, SQLDMO) */
/* - sp_droptask (INSTREPL.SQL, INSTDIST.SQL, SQLDMO) */
/* - systasks (For completeness only) */
/**************************************************************/
/**************************************************************/
/* SP_UNIQUETASKNAME */
/**************************************************************/
PRINT ''
PRINT 'Creating [legacy] procedure sp_uniquetaskname...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_uniquetaskname')
AND (type = 'P')))
DROP PROCEDURE sp_uniquetaskname
go
CREATE PROCEDURE sp_uniquetaskname
@seed NVARCHAR(92)
AS
BEGIN
DECLARE @newest_suffix INT
SET NOCOUNT ON
-- We're going to add a suffix of 8 characters so make sure the seed is at most 84 characters
SELECT @seed = LTRIM(RTRIM(@seed))
IF (DATALENGTH(@seed) > 0)
SELECT @seed = SUBSTRING(@seed, 1, 84)
-- Find the newest (highest) suffix so far
SELECT @newest_suffix = MAX(CONVERT(INT, RIGHT(name, 8)))
FROM msdb.dbo.sysjobs -- DON'T use sysjobs_view here!
WHERE (name LIKE N'%[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')
-- Generate the task name by appending the 'newest suffix' value (plus one) to the seed
IF (@newest_suffix IS NOT NULL)
BEGIN
SELECT @newest_suffix = @newest_suffix + 1
SELECT 'TaskName' = CONVERT(NVARCHAR(92), @seed + REPLICATE(N'0', 8 - (DATALENGTH(CONVERT(NVARCHAR, @newest_suffix)) / 2)) + CONVERT(NVARCHAR, @newest_suffix))
END
ELSE
SELECT 'TaskName' = CONVERT(NVARCHAR(92), @seed + N'00000001')
END
go
/**************************************************************/
/* SP_ADDTASK */
/**************************************************************/
PRINT ''
PRINT 'Creating [legacy] procedure sp_addtask...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_addtask')
AND (type = 'P')))
DROP PROCEDURE sp_addtask
go
CREATE PROCEDURE sp_addtask
@name sysname, -- Was VARCHAR(100) in 6.x
@subsystem NVARCHAR(40) = N'TSQL', -- Was VARCHAR(30) in 6.x
@server sysname = NULL,
@username sysname = NULL, -- Was VARCHAR(30) in 6.x
@databasename sysname = NULL, -- Was VARCHAR(30) in 6.x
@enabled TINYINT = 0,
@freqtype INT = 2, -- 2 means OnDemand
@freqinterval INT = 1,
@freqsubtype INT = 1,
@freqsubinterval INT = 1,
@freqrelativeinterval INT = 1,
@freqrecurrencefactor INT = 1,
@activestartdate INT = 0,
@activeenddate INT = 0,
@activestarttimeofday INT = 0,
@activeendtimeofday INT = 0,
@nextrundate INT = 0,
@nextruntime INT = 0,
@runpriority INT = 0,
@emailoperatorname sysname = NULL, -- Was VARCHAR(50) in 6.x
@retryattempts INT = 0,
@retrydelay INT = 10,
@command NVARCHAR(max) = NULL,
@loghistcompletionlevel INT = 2,
@emailcompletionlevel INT = 0,
@description NVARCHAR(512) = NULL, -- Was VARCHAR(255) in 6.x
@tagadditionalinfo VARCHAR(96) = NULL, -- Obsolete in 7.0
@tagobjectid INT = NULL, -- Obsolete in 7.0
@tagobjecttype INT = NULL, -- Obsolete in 7.0
@newid INT = NULL OUTPUT,
@parameters NVARCHAR(max) = NULL, -- Was TEXT in 6.x
@cmdexecsuccesscode INT = 0,
@category_name sysname = NULL, -- New for 7.0
@category_id INT = NULL -- New for 7.0
AS
BEGIN
DECLARE @retval INT
DECLARE @job_id UNIQUEIDENTIFIER
DECLARE @id INT
DECLARE @distdb sysname
DECLARE @proc nvarchar(255)
SET NOCOUNT ON
SELECT @retval = 1 -- 0 means success, 1 means failure
-- Set 7.0 category names for 6.5 replication tasks
IF (LOWER(@subsystem) = N'sync')
SELECT @category_id = 15
ELSE IF (LOWER(@subsystem) = N'logreader')
SELECT @category_id = 13
ELSE IF (LOWER(@subsystem) = N'distribution')
SELECT @category_id = 10
-- Convert old replication synchronization subsystem name to the 7.0 name
IF (LOWER(@subsystem) = N'sync')
SELECT @subsystem = N'Snapshot'
-- If a category ID is provided this overrides any supplied category name
IF (@category_id IS NOT NULL)
BEGIN
SELECT @category_name = name
FROM msdb.dbo.syscategories
WHERE (category_id = @category_id)
SELECT @category_name = ISNULL(@category_name, FORMATMESSAGE(14205))
END
-- In 6.x active start date was not restricted, but it is in 7.0; so to avoid a "noisey"
-- failure in sp_add_jobschedule we modify the value accordingly
IF ((@activestartdate <> 0) AND (@activestartdate < 19900101))
SELECT @activestartdate = 19900101
BEGIN TRANSACTION
-- Add the job
EXECUTE @retval = sp_add_job
@job_name = @name,
@enabled = @enabled,
@start_step_id = 1,
@description = @description,
@category_name = @category_name,
@notify_level_eventlog = @loghistcompletionlevel,
@notify_level_email = @emailcompletionlevel,
@notify_email_operator_name = @emailoperatorname,
@job_id = @job_id OUTPUT
IF (@retval <> 0)
BEGIN
ROLLBACK TRANSACTION
GOTO Quit
END
-- Add an entry to systaskids for the new job (created by a 6.x client)
INSERT INTO msdb.dbo.systaskids (job_id) VALUES (@job_id)
-- Get the assigned task id
SELECT @id = task_id, @newid = task_id
FROM msdb.dbo.systaskids
WHERE (job_id = @job_id)
-- Add the job step
EXECUTE @retval = sp_add_jobstep
@job_id = @job_id,
@step_id = 1,
@step_name = N'Step 1',
@subsystem = @subsystem,
@command = @command,
@additional_parameters = @parameters,
@cmdexec_success_code = @cmdexecsuccesscode,
@server = @server,
@database_name = @databasename,
@database_user_name = @username,
@retry_attempts = @retryattempts,
@retry_interval = @retrydelay,
@os_run_priority = @runpriority
IF (@retval <> 0)
BEGIN
ROLLBACK TRANSACTION
GOTO Quit
END
-- Add the job schedule
IF (@activestartdate = 0)
SELECT @activestartdate = NULL
IF (@activeenddate = 0)
SELECT @activeenddate = NULL
IF (@activestarttimeofday = 0)
SELECT @activestarttimeofday = NULL
IF (@activeendtimeofday = 0)
SELECT @activeendtimeofday = NULL
IF (@freqtype <> 0x2) -- OnDemand tasks simply have no schedule in 7.0
BEGIN
EXECUTE @retval = sp_add_jobschedule
@job_id = @job_id,
@name = N'6.x schedule',
@enabled = 1,
@freq_type = @freqtype,
@freq_interval = @freqinterval,
@freq_subday_type = @freqsubtype,
@freq_subday_interval = @freqsubinterval,
@freq_relative_interval = @freqrelativeinterval,
@freq_recurrence_factor = @freqrecurrencefactor,
@active_start_date = @activestartdate,
@active_end_date = @activeenddate,
@active_start_time = @activestarttimeofday,
@active_end_time = @activeendtimeofday
IF (@retval <> 0)
BEGIN
ROLLBACK TRANSACTION
GOTO Quit
END
END
-- And finally, add the job server
EXECUTE @retval = sp_add_jobserver @job_id = @job_id, @server_name = NULL
IF (@retval <> 0)
BEGIN
ROLLBACK TRANSACTION
GOTO Quit
END
-- Add the replication agent for monitoring
IF (@category_id = 13) -- Logreader
BEGIN
SELECT @distdb = distribution_db from MSdistpublishers where name = @server
SELECT @proc = @distdb + '.dbo.sp_MSadd_logreader_agent'
EXECUTE @retval = @proc
@name = @name,
@publisher = @server,
@publisher_db = @databasename,
@publication = '',
@local_job = 1,
@job_existing = 1,
@job_id = @job_id
IF (@retval <> 0)
BEGIN
ROLLBACK TRANSACTION
GOTO Quit
END
END
ELSE
IF (@category_id = 15) -- Snapshot
BEGIN
DECLARE @publication sysname
EXECUTE @retval = master.dbo.sp_MSget_publication_from_taskname
@taskname = @name,
@publisher = @server,
@publisherdb = @databasename,
@publication = @publication OUTPUT
IF (@publication IS NOT NULL)
BEGIN
SELECT @distdb = distribution_db from MSdistpublishers where name = @server
SELECT @proc = @distdb + '.dbo.sp_MSadd_snapshot_agent'
EXECUTE @retval = @proc
@name = @name,
@publisher = @server,
@publisher_db = @databasename,
@publication = @publication,
@local_job = 1,
@job_existing = 1,
@snapshot_jobid = @job_id
IF (@retval <> 0)
BEGIN
ROLLBACK TRANSACTION
GOTO Quit
END
SELECT @proc = @distdb + '.dbo.sp_MSadd_publication'
EXECUTE @retval = @proc
@publisher = @server,
@publisher_db = @databasename,
@publication = @publication,
@publication_type = 0 -- Transactional
IF (@retval <> 0)
BEGIN
ROLLBACK TRANSACTION
GOTO Quit
END
END
END
COMMIT TRANSACTION
-- If this is an autostart LogReader or Distribution job, add the [new] '-Continuous' paramter to the command
IF (@freqtype = 0x40) AND ((UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'LOGREADER') OR (UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'DISTRIBUTION'))
BEGIN
UPDATE msdb.dbo.sysjobsteps
SET command = command + N' -Continuous'
WHERE (job_id = @job_id)
AND (step_id = 1)
END
-- If this is an autostart job, start it now (for backwards compatibility with 6.x SQLExecutive behaviour)
IF (@freqtype = 0x40)
EXECUTE msdb.dbo.sp_start_job @job_id = @job_id, @error_flag = 0, @output_flag = 0
Quit:
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_DROPTASK */
/**************************************************************/
PRINT ''
PRINT 'Creating [legacy] procedure sp_droptask...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_droptask')
AND (type = 'P')))
DROP PROCEDURE sp_droptask
go
CREATE PROCEDURE sp_droptask
@name sysname = NULL, -- Was VARCHAR(100) in 6.x
@loginname sysname = NULL, -- Was VARCHAR(30) in 6.x
@id INT = NULL
AS
BEGIN
DECLARE @retval INT
DECLARE @job_id UNIQUEIDENTIFIER
DECLARE @category_id int
SET NOCOUNT ON
IF ((@name IS NULL) AND (@id IS NULL) AND (@loginname IS NULL)) OR
((@name IS NOT NULL) AND ((@id IS NOT NULL) OR (@loginname IS NOT NULL))) OR
((@id IS NOT NULL) AND ((@name IS NOT NULL) OR (@loginname IS NOT NULL))) OR
((@loginname IS NOT NULL) AND ((@name IS NOT NULL) OR (@id IS NOT NULL)))
BEGIN
RAISERROR(14245, -1, -1)
RETURN(1) -- Failure
END
-- If the name is supplied, get the job_id directly from sysjobs
IF (@name IS NOT NULL)
BEGIN
-- Check if the name is ambiguous
IF ((SELECT COUNT(*)
FROM msdb.dbo.sysjobs_view
WHERE (name = @name)) > 1)
BEGIN
RAISERROR(14292, -1, -1, @name, '@id', '@name')
RETURN(1) -- Failure
END
SELECT @job_id = job_id, @category_id = category_id
FROM msdb.dbo.sysjobs_view
WHERE (name = @name)
SELECT @id = task_id
FROM msdb.dbo.systaskids
WHERE (job_id = @job_id)
IF (@job_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
END
-- If the id is supplied lookup the corresponding job_id from systaskids
IF (@id IS NOT NULL)
BEGIN
SELECT @job_id = job_id
FROM msdb.dbo.systaskids
WHERE (task_id = @id)
-- Check that the job still exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysjobs_view
WHERE (job_id = @job_id)))
BEGIN
SELECT @name = CONVERT(NVARCHAR, @id)
RAISERROR(14262, -1, -1, '@id', @name)
RETURN(1) -- Failure
END
-- Get the name of this job
SELECT @name = name, @category_id = category_id
FROM msdb.dbo.sysjobs_view
WHERE (job_id = @job_id)
END
-- Delete the specific job
IF (@name IS NOT NULL)
BEGIN
BEGIN TRANSACTION
DELETE FROM msdb.dbo.systaskids
WHERE (job_id = @job_id)
EXECUTE @retval = sp_delete_job @job_id = @job_id
IF (@retval <> 0)
BEGIN
ROLLBACK TRANSACTION
GOTO Quit
END
-- If a Logreader or Snapshot task, delete corresponding replication agent information
IF @category_id = 13 or @category_id = 15
BEGIN
EXECUTE @retval = sp_MSdrop_6x_replication_agent @job_id, @category_id
IF (@retval <> 0)
BEGIN
ROLLBACK TRANSACTION
GOTO Quit
END
END
COMMIT TRANSACTION
END
-- Delete all jobs belonging to the specified login
IF (@loginname IS NOT NULL)
BEGIN
BEGIN TRANSACTION
DELETE FROM msdb.dbo.systaskids
WHERE job_id IN (SELECT job_id
FROM msdb.dbo.sysjobs_view
WHERE (owner_sid = SUSER_SID(@loginname)))
EXECUTE @retval = sp_manage_jobs_by_login @action = 'DELETE',
@current_owner_login_name = @loginname
IF (@retval <> 0)
BEGIN
ROLLBACK TRANSACTION
GOTO Quit
END
COMMIT TRANSACTION
END
Quit:
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* */
/* E R R O R M E S S A G E S */
/* */
/* These are now created by MESSAGES.SQL. */
/* */
/* NOTE: 14255 and 14265 are called by dynamic SQL generated */
/* by SQLServerAgent. */
/**************************************************************/
/**************************************************************/
/* */
/* T R I G G E R S */
/* */
/**************************************************************/
/**************************************************************/
/* TRIG_TARGETSERVER_INSERT */
/**************************************************************/
PRINT ''
PRINT 'Creating trigger trig_targetserver_insert...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'trig_targetserver_insert')
AND (type = 'TR')))
DROP TRIGGER dbo.trig_targetserver_insert
go
CREATE TRIGGER trig_targetserver_insert
ON msdb.dbo.systargetservers
FOR INSERT, DELETE
AS
BEGIN
SET NOCOUNT ON
-- Disallow the insert if the server is called 'ALL'
-- NOTE: We have to do this check here in the trigger since there is no sp_add_targetserver
-- (target servers insert a row for themselves when they 'enlist' in an MSX)
IF (EXISTS (SELECT *
FROM inserted
WHERE (server_name = N'ALL')))
BEGIN
DELETE FROM msdb.dbo.systargetservers
WHERE (server_name = N'ALL')
RAISERROR(14271, -1, -1, 'ALL')
RETURN
END
-- Set (or delete) the registy flag (so that SETUP can detect if we're an MSX)
IF ((SELECT COUNT(*)
FROM msdb.dbo.systargetservers) = 0)
BEGIN
DECLARE @val INT
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServer',
@val OUTPUT,
N'no_output'
IF (@val IS NOT NULL)
EXECUTE master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServer'
END
ELSE
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServer',
N'REG_DWORD',
1
END
go
CHECKPOINT
go
/**************************************************************/
/** **/
/** A L E R T S A N D O P E R A T O R S **/
/** **/
/**************************************************************/
/**************************************************************/
/* */
/* C O R E P R O C E D U R E S */
/* */
/**************************************************************/
/**************************************************************/
/* SP_ADD_ALERT_INTERNAL */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_alert_internal...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_alert_internal')
AND (type = 'P')))
DROP PROCEDURE sp_add_alert_internal
go
CREATE PROCEDURE sp_add_alert_internal
@name sysname,
@message_id INT = 0,
@severity INT = 0,
@enabled TINYINT = 1,
@delay_between_responses INT = 0,
@notification_message NVARCHAR(512) = NULL,
@include_event_description_in TINYINT = 5, -- 0 = None, 1 = Email, 2 = Pager, 4 = NetSend, 7 = All
@database_name sysname = NULL,
@event_description_keyword NVARCHAR(100) = NULL,
@job_id UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name
@job_name sysname = NULL, -- If provided must NOT also provide job_id
@raise_snmp_trap TINYINT = 0,
@performance_condition NVARCHAR(512) = NULL, -- New for 7.0
@category_name sysname = NULL, -- New for 7.0
@wmi_namespace NVARCHAR(512) = NULL, -- New for 9.0
@wmi_query NVARCHAR(512) = NULL, -- New for 9.0
@verify_alert TINYINT = 1 -- 0 = do not verify alert, 1(or anything else) = verify alert before adding
AS
BEGIN
DECLARE @event_source NVARCHAR(100)
DECLARE @event_category_id INT
DECLARE @event_id INT
DECLARE @last_occurrence_date INT
DECLARE @last_occurrence_time INT
DECLARE @last_notification_date INT
DECLARE @last_notification_time INT
DECLARE @occurrence_count INT
DECLARE @count_reset_date INT
DECLARE @count_reset_time INT
DECLARE @has_notification INT
DECLARE @return_code INT
DECLARE @duplicate_name sysname
DECLARE @category_id INT
DECLARE @alert_id INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
SELECT @notification_message = LTRIM(RTRIM(@notification_message))
SELECT @database_name = LTRIM(RTRIM(@database_name))
SELECT @event_description_keyword = LTRIM(RTRIM(@event_description_keyword))
SELECT @job_name = LTRIM(RTRIM(@job_name))
SELECT @performance_condition = LTRIM(RTRIM(@performance_condition))
SELECT @category_name = LTRIM(RTRIM(@category_name))
-- Turn [nullable] empty string parameters into NULLs
IF (@notification_message = N'') SELECT @notification_message = NULL
IF (@database_name = N'') SELECT @database_name = NULL
IF (@event_description_keyword = N'') SELECT @event_description_keyword = NULL
IF (@job_name = N'') SELECT @job_name = NULL
IF (@performance_condition = N'') SELECT @performance_condition = NULL
IF (@category_name = N'') SELECT @category_name = NULL
SELECT @message_id = ISNULL(@message_id, 0)
SELECT @severity = ISNULL(@severity, 0)
-- Only a sysadmin can do this
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Check if SQLServerAgent is in the process of starting
EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting
IF (@return_code <> 0)
RETURN(1) -- Failure
-- Hard-code the new Alert defaults
-- event source needs to be instance aware
DECLARE @instance_name sysname
SELECT @instance_name = CONVERT (sysname, SERVERPROPERTY ('InstanceName'))
IF (@instance_name IS NULL OR @instance_name = N'MSSQLSERVER')
SELECT @event_source = N'MSSQLSERVER'
ELSE
SELECT @event_source = N'MSSQL$' + @instance_name
SELECT @event_category_id = NULL
SELECT @event_id = NULL
SELECT @last_occurrence_date = 0
SELECT @last_occurrence_time = 0
SELECT @last_notification_date = 0
SELECT @last_notification_time = 0
SELECT @occurrence_count = 0
SELECT @count_reset_date = 0
SELECT @count_reset_time = 0
SELECT @has_notification = 0
IF (@category_name IS NULL)
BEGIN
--Default category_id for alerts
SELECT @category_id = 98
SELECT @category_name = name
FROM msdb.dbo.syscategories
WHERE (category_id = 98)
END
-- Map a job_id of 0 to the real value we use to mean 'no job'
IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00)) AND (@job_name IS NULL)
SELECT @job_name = N''
-- Verify the Alert if @verify_alert <> 0
IF (@verify_alert <> 0)
BEGIN
IF (@job_id = CONVERT(UNIQUEIDENTIFIER, 0x00))
SELECT @job_id = NULL
EXECUTE @return_code = sp_verify_alert @name,
@message_id,
@severity,
@enabled,
@delay_between_responses,
@notification_message,
@include_event_description_in,
@database_name,
@event_description_keyword,
@job_id OUTPUT,
@job_name OUTPUT,
@occurrence_count,
@raise_snmp_trap,
@performance_condition,
@category_name,
@category_id OUTPUT,
@count_reset_date,
@count_reset_time,
@wmi_namespace,
@wmi_query,
@event_id OUTPUT
IF (@return_code <> 0)
BEGIN
RETURN(1) -- Failure
END
END
-- For WMI alerts replace
-- database_name with wmi_namespace and
-- performance_conditon with wmi_query
-- so we can store them in those columns in sysalerts table
IF (@event_id = 8)
BEGIN
SELECT @database_name = @wmi_namespace
SELECT @performance_condition = @wmi_query
END
-- Check if this Alert already exists
SELECT @duplicate_name = FORMATMESSAGE(14205)
SELECT @duplicate_name = name
FROM msdb.dbo.sysalerts
WHERE ((event_id = 8) AND
(ISNULL(performance_condition, N'') = ISNULL(@performance_condition, N'')) AND
(ISNULL(database_name, N'') = ISNULL(@database_name, N''))) OR
((ISNULL(event_id,1) <> 8) AND
(ISNULL(performance_condition, N'apples') = ISNULL(@performance_condition, N'oranges'))) OR
((performance_condition IS NULL) AND
(message_id = @message_id) AND
(severity = @severity) AND
(ISNULL(database_name, N'') = ISNULL(@database_name, N'')) AND
(ISNULL(event_description_keyword, N'') = ISNULL(@event_description_keyword, N'')))
IF (@duplicate_name <> FORMATMESSAGE(14205))
BEGIN
RAISERROR(14501, 16, 1, @duplicate_name)
RETURN(1) -- Failure
END
-- Finally, do the actual INSERT
INSERT INTO msdb.dbo.sysalerts
(name,
event_source,
event_category_id,
event_id,
message_id,
severity,
enabled,
delay_between_responses,
last_occurrence_date,
last_occurrence_time,
last_response_date,
last_response_time,
notification_message,
include_event_description,
database_name,
event_description_keyword,
occurrence_count,
count_reset_date,
count_reset_time,
job_id,
has_notification,
flags,
performance_condition,
category_id)
VALUES (@name,
@event_source,
@event_category_id,
@event_id,
@message_id,
@severity,
@enabled,
@delay_between_responses,
@last_occurrence_date,
@last_occurrence_time,
@last_notification_date,
@last_notification_time,
@notification_message,
@include_event_description_in,
@database_name,
@event_description_keyword,
@occurrence_count,
@count_reset_date,
@count_reset_time,
ISNULL(@job_id, CONVERT(UNIQUEIDENTIFIER, 0x00)),
@has_notification,
@raise_snmp_trap,
@performance_condition,
@category_id)
-- Notify SQLServerAgent of the change
SELECT @alert_id = id
FROM msdb.dbo.sysalerts
WHERE (name = @name)
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',
@alert_id = @alert_id,
@action_type = N'I'
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_ADD_ALERT */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_alert...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_alert')
AND (type = 'P')))
DROP PROCEDURE sp_add_alert
go
CREATE PROCEDURE sp_add_alert
@name sysname,
@message_id INT = 0,
@severity INT = 0,
@enabled TINYINT = 1,
@delay_between_responses INT = 0,
@notification_message NVARCHAR(512) = NULL,
@include_event_description_in TINYINT = 5, -- 0 = None, 1 = Email, 2 = Pager, 4 = NetSend, 7 = All
@database_name sysname = NULL,
@event_description_keyword NVARCHAR(100) = NULL,
@job_id UNIQUEIDENTIFIER = NULL, -- If provided must NOT also provide job_name
@job_name sysname = NULL, -- If provided must NOT also provide job_id
@raise_snmp_trap TINYINT = 0,
@performance_condition NVARCHAR(512) = NULL, -- New for 7.0
@category_name sysname = NULL, -- New for 7.0
@wmi_namespace sysname = NULL, -- New for 9.0
@wmi_query NVARCHAR(512) = NULL -- New for 9.0
AS
BEGIN
DECLARE @verify_alert INT
--Always verify alerts before adding
SELECT @verify_alert = 1
EXECUTE msdb.dbo.sp_add_alert_internal @name,
@message_id,
@severity,
@enabled,
@delay_between_responses,
@notification_message,
@include_event_description_in,
@database_name,
@event_description_keyword,
@job_id,
@job_name,
@raise_snmp_trap,
@performance_condition,
@category_name,
@wmi_namespace,
@wmi_query,
@verify_alert
END
GO
/**************************************************************/
/* SP_DELETE_ALERT */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_alert...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_alert')
AND (type = 'P')))
DROP PROCEDURE sp_delete_alert
go
CREATE PROCEDURE sp_delete_alert
@name sysname
AS
BEGIN
DECLARE @alert_id INT
DECLARE @return_code INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
-- Only a sysadmin can do this
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Check if SQLServerAgent is in the process of starting
EXECUTE @return_code = msdb.dbo.sp_is_sqlagent_starting
IF (@return_code <> 0)
RETURN(1) -- Failure
-- Check if this Alert exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysalerts
WHERE (name = @name)))
BEGIN
RAISERROR(14262, 16, 1, '@name', @name)
RETURN(1) -- Failure
END
-- Convert the Name to it's ID
SELECT @alert_id = id
FROM msdb.dbo.sysalerts
WHERE (name = @name)
BEGIN TRANSACTION
-- Delete sysnotifications entries
DELETE FROM msdb.dbo.sysnotifications
WHERE (alert_id = @alert_id)
-- Finally, do the actual DELETE
DELETE FROM msdb.dbo.sysalerts
WHERE (id = @alert_id)
COMMIT TRANSACTION
-- Notify SQLServerAgent of the change
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',
@alert_id = @alert_id,
@action_type = N'D'
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_HELP_ALERT */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_alert...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_alert')
AND (type = 'P')))
DROP PROCEDURE sp_help_alert
go
CREATE PROCEDURE sp_help_alert
@alert_name sysname = NULL,
@order_by sysname = N'name',
@alert_id INT = NULL,
@category_name sysname = NULL,
@legacy_format BIT = 0
AS
BEGIN
DECLARE @alert_id_as_char NVARCHAR(10)
DECLARE @escaped_alert_name NVARCHAR(256) -- double sysname
DECLARE @escaped_category_name NVARCHAR(256) -- double sysname
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @alert_name = LTRIM(RTRIM(@alert_name))
SELECT @order_by = LTRIM(RTRIM(@order_by))
SELECT @category_name = LTRIM(RTRIM(@category_name))
-- Turn [nullable] empty string parameters into NULLs
IF (@category_name = N'') SELECT @category_name = NULL
IF (@alert_name = N'') SELECT @alert_name = NULL
-- Check alert name
IF (@alert_name IS NOT NULL)
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysalerts
WHERE (name = @alert_name)))
BEGIN
RAISERROR(14262, -1, -1, '@alert_name', @alert_name)
RETURN(1) -- Failure
END
END
-- Check alert id
IF (@alert_id IS NOT NULL)
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysalerts
WHERE (id = @alert_id)))
BEGIN
SELECT @alert_id_as_char = CONVERT(VARCHAR, @alert_id)
RAISERROR(14262, -1, -1, '@alert_id', @alert_id_as_char)
RETURN(1) -- Failure
END
END
IF (@alert_id IS NOT NULL)
SELECT @alert_id_as_char = CONVERT(VARCHAR, @alert_id)
ELSE
SELECT @alert_id_as_char = N'NULL'
-- Double up any single quotes in @alert_name
IF (@alert_name IS NOT NULL)
SELECT @escaped_alert_name = REPLACE(@alert_name, N'''', N'''''')
-- Double up any single quotes in @category_name
IF (@category_name IS NOT NULL)
SELECT @escaped_category_name = REPLACE(@category_name, N'''', N'''''')
IF (@legacy_format <> 0)
BEGIN
-- @order_by parameter validation.
IF ( (@order_by IS NOT NULL) AND
(EXISTS(SELECT so.object_id FROM msdb.sys.objects so
JOIN msdb.sys.columns sc ON (so.object_id = sc.object_id)
WHERE so.type='U' AND so.name='sysalerts'
AND LOWER(sc.name collate SQL_Latin1_General_CP1_CS_AS)=LOWER(@order_by collate SQL_Latin1_General_CP1_CS_AS)
)
) )
BEGIN
SELECT @order_by = N'sa.' + @order_by
END
ELSE
BEGIN
IF (LOWER(@order_by collate SQL_Latin1_General_CP1_CS_AS) NOT IN ( N'job_name', N'category_name', N'type' ) )
AND --special "order by" clause used only by sqlagent. if you change it you need to change agent too
(@order_by <> N'event_id DESC, severity ASC, message_id ASC, database_name DESC')
AND
(@order_by <> N'severity ASC, message_id ASC, database_name DESC')
BEGIN
RAISERROR(18750, -1, -1, 'sp_help_alert', '@order_by')
RETURN(1) -- Failure
END
END
-- Old query version (for SQL Server 2000 and older servers)
-- database_name and performance_conditions are reported
-- directly from sysalerts columns
EXECUTE (N'SELECT sa.id,
sa.name,
sa.event_source,
sa.event_category_id,
sa.event_id,
sa.message_id,
sa.severity,
sa.enabled,
sa.delay_between_responses,
sa.last_occurrence_date,
sa.last_occurrence_time,
sa.last_response_date,
sa.last_response_time,
sa.notification_message,
sa.include_event_description,
sa.database_name,
sa.event_description_keyword,
sa.occurrence_count,
sa.count_reset_date,
sa.count_reset_time,
sjv.job_id,
job_name = sjv.name,
sa.has_notification,
sa.flags,
sa.performance_condition,
category_name = sc.name,
type = CASE ISNULL(sa.performance_condition, ''!'')
WHEN ''!'' THEN 1 -- SQL Server event alert
ELSE CASE sa.event_id
WHEN 8 THEN 4 -- WMI event alert
ELSE 2 -- SQL Server performance condition alert
END
END
FROM msdb.dbo.sysalerts sa
LEFT OUTER JOIN msdb.dbo.sysjobs_view sjv ON (sa.job_id = sjv.job_id)
LEFT OUTER JOIN msdb.dbo.syscategories sc ON (sa.category_id = sc.category_id)
WHERE ((N''' + @escaped_alert_name + N''' = N'''') OR (sa.name = N''' + @escaped_alert_name + N'''))
AND ((' + @alert_id_as_char + N' IS NULL) OR (sa.id = ' + @alert_id_as_char + N'))
AND ((N''' + @escaped_category_name + N''' = N'''') OR (sc.name = N''' + @escaped_category_name + N'''))
ORDER BY ' + @order_by)
END
ELSE
BEGIN
-- @order_by parameter validation.
IF ( (@order_by IS NOT NULL) AND
(EXISTS(SELECT so.object_id FROM msdb.sys.objects so
JOIN msdb.sys.columns sc ON (so.object_id = sc.object_id)
WHERE so.type='U' AND so.name='sysalerts'
AND LOWER(sc.name collate SQL_Latin1_General_CP1_CS_AS)=LOWER(@order_by collate SQL_Latin1_General_CP1_CS_AS)
)
) )
BEGIN
SELECT @order_by = N'sa.' + @order_by
END
ELSE
BEGIN
IF (LOWER(@order_by collate SQL_Latin1_General_CP1_CS_AS) NOT IN (N'database_name', N'job_name', N'performance_condition', N'category_name', N'wmi_namespace', N'wmi_query', N'type' ) )
AND --special "order by" clause used only by sqlagent. if you change it you need to change agent too
(@order_by <> N'event_id DESC, severity ASC, message_id ASC, database_name DESC')
AND
(@order_by <> N'severity ASC, message_id ASC, database_name DESC')
BEGIN
RAISERROR(18750, -1, -1, 'sp_help_alert', '@order_by')
RETURN(1) -- Failure
END
END
-- New query version. If alert is a WMI alert
-- then database_name is reported as wmi_namespace and
-- performance_condition is reported as wmi_query.
-- For other alerts those two new columns are NULL
EXECUTE (N'SELECT sa.id,
sa.name,
sa.event_source,
sa.event_category_id,
sa.event_id,
sa.message_id,
sa.severity,
sa.enabled,
sa.delay_between_responses,
sa.last_occurrence_date,
sa.last_occurrence_time,
sa.last_response_date,
sa.last_response_time,
sa.notification_message,
sa.include_event_description,
database_name = CASE ISNULL(sa.event_id, 1)
WHEN 8 THEN NULL
ELSE sa.database_name
END,
sa.event_description_keyword,
sa.occurrence_count,
sa.count_reset_date,
sa.count_reset_time,
sjv.job_id,
job_name = sjv.name,
sa.has_notification,
sa.flags,
performance_condition = CASE ISNULL(sa.event_id, 1)
WHEN 8 THEN NULL
ELSE sa.performance_condition
END,
category_name = sc.name,
wmi_namespace = CASE ISNULL(sa.event_id, 1)
WHEN 8 THEN sa.database_name
ELSE NULL
END,
wmi_query = CASE ISNULL(sa.event_id, 1)
WHEN 8 THEN sa.performance_condition
ELSE NULL
END,
type = CASE ISNULL(sa.performance_condition, ''!'')
WHEN ''!'' THEN 1 -- SQL Server event alert
ELSE CASE sa.event_id
WHEN 8 THEN 4 -- WMI event alert
ELSE 2 -- SQL Server performance condition alert
END
END
FROM msdb.dbo.sysalerts sa
LEFT OUTER JOIN msdb.dbo.sysjobs_view sjv ON (sa.job_id = sjv.job_id)
LEFT OUTER JOIN msdb.dbo.syscategories sc ON (sa.category_id = sc.category_id)
WHERE ((N''' + @escaped_alert_name + N''' = N'''') OR (sa.name = N''' + @escaped_alert_name + N'''))
AND ((' + @alert_id_as_char + N' IS NULL) OR (sa.id = ' + @alert_id_as_char + N'))
AND ((N''' + @escaped_category_name + N''' = N'''') OR (sc.name = N''' + @escaped_category_name + N'''))
ORDER BY ' + @order_by)
END
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_VERIFY_OPERATOR */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_operator...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_operator')
AND (type = 'P')))
DROP PROCEDURE sp_verify_operator
go
CREATE PROCEDURE sp_verify_operator
@name sysname,
@enabled TINYINT,
@pager_days TINYINT,
@weekday_pager_start_time INT,
@weekday_pager_end_time INT,
@saturday_pager_start_time INT,
@saturday_pager_end_time INT,
@sunday_pager_start_time INT,
@sunday_pager_end_time INT,
@category_name sysname,
@category_id INT OUTPUT
AS
BEGIN
DECLARE @return_code TINYINT
DECLARE @res_valid_range NVARCHAR(100)
SET NOCOUNT ON
SELECT @res_valid_range = FORMATMESSAGE(14209)
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
SELECT @category_name = LTRIM(RTRIM(@category_name))
-- The name must be unique
IF (EXISTS (SELECT *
FROM msdb.dbo.sysoperators
WHERE (name = @name)))
BEGIN
RAISERROR(14261, 16, 1, '@name', @name)
RETURN(1) -- Failure
END
-- Enabled must be 0 or 1
IF (@enabled NOT IN (0, 1))
BEGIN
RAISERROR(14266, 16, 1, '@enabled', '0, 1')
RETURN(1) -- Failure
END
-- Check PagerDays
IF (@pager_days < 0) OR (@pager_days > 127)
BEGIN
RAISERROR(14266, 16, 1, '@pager_days', @res_valid_range)
RETURN(1) -- Failure
END
-- Check Start/End Times
EXECUTE @return_code = sp_verify_job_time @weekday_pager_start_time, '@weekday_pager_start_time'
IF (@return_code <> 0)
RETURN(1)
EXECUTE @return_code = sp_verify_job_time @weekday_pager_end_time, '@weekday_pager_end_time'
IF (@return_code <> 0)
RETURN(1)
EXECUTE @return_code = sp_verify_job_time @saturday_pager_start_time, '@saturday_pager_start_time'
IF (@return_code <> 0)
RETURN(1)
EXECUTE @return_code = sp_verify_job_time @saturday_pager_end_time, '@saturday_pager_end_time'
IF (@return_code <> 0)
RETURN(1)
EXECUTE @return_code = sp_verify_job_time @sunday_pager_start_time, '@sunday_pager_start_time'
IF (@return_code <> 0)
RETURN(1)
EXECUTE @return_code = sp_verify_job_time @sunday_pager_end_time, '@sunday_pager_end_time'
IF (@return_code <> 0)
RETURN(1)
-- Check category name
IF (@category_name = N'[DEFAULT]')
SELECT @category_id = 99
ELSE
BEGIN
SELECT @category_id = category_id
FROM msdb.dbo.syscategories
WHERE (category_class = 3) -- Operators
AND (category_type = 3) -- None
AND (name = @category_name)
END
IF (@category_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@category_name', @category_name)
RETURN(1) -- Failure
END
RETURN(0)
END
go
/**************************************************************/
/* SP_ADD_OPERATOR */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_operator...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_operator')
AND (type = 'P')))
DROP PROCEDURE sp_add_operator
go
CREATE PROCEDURE sp_add_operator
@name sysname,
@enabled TINYINT = 1,
@email_address NVARCHAR(100) = NULL,
@pager_address NVARCHAR(100) = NULL,
@weekday_pager_start_time INT = 090000, -- HHMMSS using 24 hour clock
@weekday_pager_end_time INT = 180000, -- As above
@saturday_pager_start_time INT = 090000, -- As above
@saturday_pager_end_time INT = 180000, -- As above
@sunday_pager_start_time INT = 090000, -- As above
@sunday_pager_end_time INT = 180000, -- As above
@pager_days TINYINT = 0, -- 1 = Sunday .. 64 = Saturday
@netsend_address NVARCHAR(100) = NULL, -- New for 7.0
@category_name sysname = NULL -- New for 7.0
AS
BEGIN
DECLARE @return_code TINYINT
DECLARE @category_id INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
SELECT @email_address = LTRIM(RTRIM(@email_address))
SELECT @pager_address = LTRIM(RTRIM(@pager_address))
SELECT @netsend_address = LTRIM(RTRIM(@netsend_address))
SELECT @category_name = LTRIM(RTRIM(@category_name))
-- Turn [nullable] empty string parameters into NULLs
IF (@email_address = N'') SELECT @email_address = NULL
IF (@pager_address = N'') SELECT @pager_address = NULL
IF (@netsend_address = N'') SELECT @netsend_address = NULL
IF (@category_name = N'') SELECT @category_name = NULL
-- Only a sysadmin can do this
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
IF (@category_name IS NULL)
BEGIN
SELECT @category_name = name
FROM msdb.dbo.syscategories
WHERE (category_id = 99)
END
-- Verify the operator
EXECUTE @return_code = sp_verify_operator @name,
@enabled,
@pager_days,
@weekday_pager_start_time,
@weekday_pager_end_time,
@saturday_pager_start_time,
@saturday_pager_end_time,
@sunday_pager_start_time,
@sunday_pager_end_time,
@category_name,
@category_id OUTPUT
IF (@return_code <> 0)
RETURN(1) -- Failure
-- Finally, do the INSERT
INSERT INTO msdb.dbo.sysoperators
(name,
enabled,
email_address,
last_email_date,
last_email_time,
pager_address,
last_pager_date,
last_pager_time,
weekday_pager_start_time,
weekday_pager_end_time,
saturday_pager_start_time,
saturday_pager_end_time,
sunday_pager_start_time,
sunday_pager_end_time,
pager_days,
netsend_address,
last_netsend_date,
last_netsend_time,
category_id)
VALUES (@name,
@enabled,
@email_address,
0,
0,
@pager_address,
0,
0,
@weekday_pager_start_time,
@weekday_pager_end_time,
@saturday_pager_start_time,
@saturday_pager_end_time,
@sunday_pager_start_time,
@sunday_pager_end_time,
@pager_days,
@netsend_address,
0,
0,
@category_id)
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_UPDATE_OPERATOR */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_operator...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_update_operator')
AND (type = 'P')))
DROP PROCEDURE sp_update_operator
go
CREATE PROCEDURE sp_update_operator
@name sysname,
@new_name sysname = NULL,
@enabled TINYINT = NULL,
@email_address NVARCHAR(100) = NULL,
@pager_address NVARCHAR(100) = NULL,
@weekday_pager_start_time INT = NULL, -- HHMMSS using 24 hour clock
@weekday_pager_end_time INT = NULL, -- As above
@saturday_pager_start_time INT = NULL, -- As above
@saturday_pager_end_time INT = NULL, -- As above
@sunday_pager_start_time INT = NULL, -- As above
@sunday_pager_end_time INT = NULL, -- As above
@pager_days TINYINT = NULL,
@netsend_address NVARCHAR(100) = NULL, -- New for 7.0
@category_name sysname = NULL -- New for 7.0
AS
BEGIN
DECLARE @x_enabled TINYINT
DECLARE @x_email_address NVARCHAR(100)
DECLARE @x_pager_address NVARCHAR(100)
DECLARE @x_weekday_pager_start_time INT
DECLARE @x_weekday_pager_end_time INT
DECLARE @x_saturday_pager_start_time INT
DECLARE @x_saturday_pager_end_time INT
DECLARE @x_sunday_pager_start_time INT
DECLARE @x_sunday_pager_end_time INT
DECLARE @x_pager_days TINYINT
DECLARE @x_netsend_address NVARCHAR(100)
DECLARE @x_category_id INT
DECLARE @return_code INT
DECLARE @notification_method INT
DECLARE @alert_fail_safe_operator sysname
DECLARE @current_msx_server sysname
DECLARE @category_id INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name = LTRIM(RTRIM(@name))
SELECT @new_name = LTRIM(RTRIM(@new_name))
SELECT @email_address = LTRIM(RTRIM(@email_address))
SELECT @pager_address = LTRIM(RTRIM(@pager_address))
SELECT @netsend_address = LTRIM(RTRIM(@netsend_address))
SELECT @category_name = LTRIM(RTRIM(@category_name))
-- Only a sysadmin can do this
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Check if this Operator exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysoperators
WHERE (name = @name)))
BEGIN
RAISERROR(14262, 16, 1, '@name', @name)
RETURN(1) -- Failure
END
-- Check if this operator is 'MSXOperator'
IF (@name = N'MSXOperator')
BEGIN
-- Disallow the update operation if we're at a TSX for all callers other than xp_msx_enlist
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'MSXServerName',
@current_msx_server OUTPUT,
N'no_output'
IF ((@current_msx_server IS NOT NULL) AND (PROGRAM_NAME() <> N'xp_msx_enlist'))
BEGIN
RAISERROR(14223, 16, 1, 'MSXOperator', 'TSX')
RETURN(1) -- Failure
END
END
-- Get existing (@x_) operator property values
SELECT @x_enabled = enabled,
@x_email_address = email_address,
@x_pager_address = pager_address,
@x_weekday_pager_start_time = weekday_pager_start_time,
@x_weekday_pager_end_time = weekday_pager_end_time,
@x_saturday_pager_start_time = saturday_pager_start_time,
@x_saturday_pager_end_time = saturday_pager_end_time,
@x_sunday_pager_start_time = sunday_pager_start_time,
@x_sunday_pager_end_time = sunday_pager_end_time,
@x_pager_days = pager_days,
@x_netsend_address = netsend_address,
@x_category_id = category_id
FROM msdb.dbo.sysoperators
WHERE (name = @name)
-- Fill out the values for all non-supplied parameters from the existsing values
IF (@enabled IS NULL) SELECT @enabled = @x_enabled
IF (@email_address IS NULL) SELECT @email_address = @x_email_address
IF (@pager_address IS NULL) SELECT @pager_address = @x_pager_address
IF (@weekday_pager_start_time IS NULL) SELECT @weekday_pager_start_time = @x_weekday_pager_start_time
IF (@weekday_pager_end_time IS NULL) SELECT @weekday_pager_end_time = @x_weekday_pager_end_time
IF (@saturday_pager_start_time IS NULL) SELECT @saturday_pager_start_time = @x_saturday_pager_start_time
IF (@saturday_pager_end_time IS NULL) SELECT @saturday_pager_end_time = @x_saturday_pager_end_time
IF (@sunday_pager_start_time IS NULL) SELECT @sunday_pager_start_time = @x_sunday_pager_start_time
IF (@sunday_pager_end_time IS NULL) SELECT @sunday_pager_end_time = @x_sunday_pager_end_time
IF (@pager_days IS NULL) SELECT @pager_days = @x_pager_days
IF (@netsend_address IS NULL) SELECT @netsend_address = @x_netsend_address
IF (@category_name IS NULL) SELECT @category_name = name FROM msdb.dbo.syscategories WHERE (category_id = @x_category_id)
IF (@category_name IS NULL)
BEGIN
SELECT @category_name = name
FROM msdb.dbo.syscategories
WHERE (category_id = 99)
END
-- Turn [nullable] empty string parameters into NULLs
IF (@email_address = N'') SELECT @email_address = NULL
IF (@pager_address = N'') SELECT @pager_address = NULL
IF (@netsend_address = N'') SELECT @netsend_address = NULL
IF (@category_name = N'') SELECT @category_name = NULL
-- Verify the operator
EXECUTE @return_code = sp_verify_operator @new_name,
@enabled,
@pager_days,
@weekday_pager_start_time,
@weekday_pager_end_time,
@saturday_pager_start_time,
@saturday_pager_end_time,
@sunday_pager_start_time,
@sunday_pager_end_time,
@category_name,
@category_id OUTPUT
IF (@return_code <> 0)
RETURN(1) -- Failure
-- If no new name is supplied, use the old one
-- NOTE: We must do this AFTER calling sp_verify_operator.
IF (@new_name IS NULL)
SELECT @new_name = @name
ELSE
BEGIN
-- You can't rename the MSXOperator
IF (@name = N'MSXOperator')
BEGIN
RAISERROR(14222, 16, 1, 'MSXOperator')
RETURN(1) -- Failure
END
END
-- Do the UPDATE
UPDATE msdb.dbo.sysoperators
SET name = @new_name,
enabled = @enabled,
email_address = @email_address,
pager_address = @pager_address,
weekday_pager_start_time = @weekday_pager_start_time,
weekday_pager_end_time = @weekday_pager_end_time,
saturday_pager_start_time = @saturday_pager_start_time,
saturday_pager_end_time = @saturday_pager_end_time,
sunday_pager_start_time = @sunday_pager_start_time,
sunday_pager_end_time = @sunday_pager_end_time,
pager_days = @pager_days,
netsend_address = @netsend_address,
category_id = @category_id
WHERE (name = @name)
-- Check if the operator is 'MSXOperator', in which case we need to re-enlist all the targets
-- so that they will download the new MSXOperator details
IF ((@name = N'MSXOperator') AND ((SELECT COUNT(*) FROM msdb.dbo.systargetservers) > 0))
EXECUTE msdb.dbo.sp_post_msx_operation 'RE-ENLIST', 'SERVER', 0x00
-- Check if this operator is the FailSafe Operator
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'AlertFailSafeOperator',
@alert_fail_safe_operator OUTPUT,
N'no_output'
-- If it is, we update the 4 'AlertFailSafe...' registry entries and AlertNotificationMethod
IF (LTRIM(RTRIM(@alert_fail_safe_operator)) = @name)
BEGIN
-- Update AlertFailSafeX values
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'AlertFailSafeOperator',
N'REG_SZ',
@new_name
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'AlertFailSafeEmailAddress',
N'REG_SZ',
@email_address
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'AlertFailSafePagerAddress',
N'REG_SZ',
@pager_address
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'AlertFailSafeNetSendAddress',
N'REG_SZ',
@netsend_address
-- Update AlertNotificationMethod values
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'AlertNotificationMethod',
@notification_method OUTPUT,
N'no_output'
IF (LTRIM(RTRIM(@email_address)) IS NULL)
SELECT @notification_method = @notification_method & ~1
IF (LTRIM(RTRIM(@pager_address)) IS NULL)
SELECT @notification_method = @notification_method & ~2
IF (LTRIM(RTRIM(@netsend_address)) IS NULL)
SELECT @notification_method = @notification_method & ~4
EXECUTE master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
N'AlertNotificationMethod',
N'REG_DWORD',
@notification_method
-- And finally, let SQLServerAgent know of the changes
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'G'
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_HELP_OPERATOR */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_operator...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_operator')
AND (type = 'P')))
DROP PROCEDURE sp_help_operator
go
CREATE PROCEDURE sp_help_operator
@operator_name sysname = NULL,
@operator_id INT = NULL
AS
BEGIN
DECLARE @operator_id_as_char VARCHAR(10)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @operator_name = LTRIM(RTRIM(@operator_name))
IF (@operator_name = '') SELECT @operator_name = NULL
-- Check operator name
IF (@operator_name IS NOT NULL)
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysoperators
WHERE (name = @operator_name)))
BEGIN
RAISERROR(14262, -1, -1, '@operator_name', @operator_name)
RETURN(1) -- Failure
END
END
-- Check operator id
IF (@operator_id IS NOT NULL)
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysoperators
WHERE (id = @operator_id)))
BEGIN
SELECT @operator_id_as_char = CONVERT(VARCHAR, @operator_id)
RAISERROR(14262, -1, -1, '@operator_id', @operator_id_as_char)
RETURN(1) -- Failure
END
END
SELECT so.id,
so.name,
so.enabled,
so.email_address,
so.last_email_date,
so.last_email_time,
so.pager_address,
so.last_pager_date,
so.last_pager_time,
so.weekday_pager_start_time,
so.weekday_pager_end_time,
so.saturday_pager_start_time,
so.saturday_pager_end_time,
so.sunday_pager_start_time,
so.sunday_pager_end_time,
so.pager_days,
so.netsend_address,
so.last_netsend_date,
so.last_netsend_time,
category_name = sc.name
FROM msdb.dbo.sysoperators so
LEFT OUTER JOIN msdb.dbo.syscategories sc ON (so.category_id = sc.category_id)
WHERE ((@operator_name IS NULL) OR (so.name = @operator_name))
AND ((@operator_id IS NULL) OR (so.id = @operator_id))
ORDER BY so.name
RETURN(@@error) -- 0 means success
END
go
/**************************************************************/
/* SP_HELP_OPERATOR_JOBS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_operator_jobs...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_help_operator_jobs')
AND (type = 'P')))
DROP PROCEDURE sp_help_operator_jobs
go
CREATE PROCEDURE sp_help_operator_jobs
@operator_name sysname = NULL
AS
BEGIN
DECLARE @operator_id INT
SET NOCOUNT ON
-- Check operator name
SELECT @operator_id = id
FROM msdb.dbo.sysoperators
WHERE (name = @operator_name)
IF (@operator_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@operator_name', @operator_name)
RETURN(1) -- Failure
END
-- Get the job info
SELECT job_id, name, notify_level_email, notify_level_netsend, notify_level_page
FROM msdb.dbo.sysjobs_view
WHERE ((notify_email_operator_id = @operator_id) AND (notify_level_email <> 0))
OR ((notify_netsend_operator_id = @operator_id) AND (notify_level_netsend <> 0))
OR ((notify_page_operator_id = @operator_id) AND (notify_level_page <> 0))
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_VERIFY_OPERATOR_IDENTIFIERS */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_operator_identifiers...'
IF (NOT OBJECT_ID(N'dbo.sp_verify_operator_identifiers', 'P') IS NULL)
DROP PROCEDURE dbo.sp_verify_operator_identifiers
go
CREATE PROCEDURE sp_verify_operator_identifiers
@name_of_name_parameter [varchar](60),
@name_of_id_parameter [varchar](60),
@operator_name [sysname] OUTPUT,
@operator_id [INT] OUTPUT
AS
BEGIN
DECLARE @retval INT
DECLARE @operator_id_as_char NVARCHAR(36)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @name_of_name_parameter = LTRIM(RTRIM(@name_of_name_parameter))
SELECT @name_of_id_parameter = LTRIM(RTRIM(@name_of_id_parameter))
SELECT @operator_name = LTRIM(RTRIM(@operator_name))
IF (@operator_name = N'') SELECT @operator_name = NULL
IF ((@operator_name IS NULL) AND (@operator_id IS NULL)) OR
((@operator_name IS NOT NULL) AND (@operator_id IS NOT NULL))
BEGIN
RAISERROR(14524, -1, -1, @name_of_id_parameter, @name_of_name_parameter)
RETURN(1) -- Failure
END
-- Check job id
IF (@operator_id IS NOT NULL)
BEGIN
SELECT @operator_name = name
FROM msdb.dbo.sysoperators
WHERE (id = @operator_id)
IF (@operator_name IS NULL)
BEGIN
SELECT @operator_id_as_char = CONVERT(nvarchar(36), @operator_id)
RAISERROR(14262, -1, -1, '@operator_id', @operator_id_as_char)
RETURN(1) -- Failure
END
END
ELSE
-- Check proxy name
IF (@operator_name IS NOT NULL)
BEGIN
-- The name is not ambiguous, so get the corresponding operator_id (if the job exists)
SELECT @operator_id = id
FROM msdb.dbo.sysoperators
WHERE (name = @operator_name)
IF (@operator_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@operator_name', @operator_name)
RETURN(1) -- Failure
END
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_NOTIFY_OPERATOR */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_notify_operator...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_notify_operator')
AND (type = 'P')))
DROP PROCEDURE sp_notify_operator
go
CREATE PROCEDURE sp_notify_operator
@profile_name sysname = NULL,
--name of Database Mail profile to be used for sending email, cannot be null
@id INT = NULL,
@name sysname = NULL,
--mutual exclusive, one and only one should be non null. Specify the operator whom mail adress will be used to send this email
@subject NVARCHAR(256) = NULL,
@body NVARCHAR(MAX) = NULL,
-- This is the body of the email message
@file_attachments NVARCHAR(512) = NULL,
@mail_database sysname = N'msdb'
-- Have infrastructure in place to support this but disabled by default
-- For first implementation we will have this parameters but using it will generate an error - not implemented yet.
AS
BEGIN
DECLARE @retval INT
DECLARE @email_address NVARCHAR(100)
DECLARE @enabled TINYINT
DECLARE @qualified_sp_sendmail sysname
DECLARE @db_id INT
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters
SELECT @profile_name = LTRIM(RTRIM(@profile_name))
SELECT @name = LTRIM(RTRIM(@name))
SELECT @file_attachments = LTRIM(RTRIM(@file_attachments))
SELECT @mail_database = LTRIM(RTRIM(@mail_database))
IF @profile_name = '' SELECT @profile_name = NULL
IF @name = '' SELECT @name = NULL
IF @file_attachments = '' SELECT @file_attachments = NULL
IF @mail_database = '' SELECT @mail_database = NULL
EXECUTE @retval = sp_verify_operator_identifiers '@name',
'@id',
@name OUTPUT,
@id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
--is operator enabled?
SELECT @enabled = enabled, @email_address = email_address FROM sysoperators WHERE id = @id
IF @enabled = 0
BEGIN
RAISERROR(14601, 16, 1, @name)
RETURN 1
END
IF @email_address IS NULL
BEGIN
RAISERROR(14602, 16, 1, @name)
RETURN 1
END
SELECT @qualified_sp_sendmail = @mail_database + '.dbo.sp_send_dbmail'
EXEC @retval = @qualified_sp_sendmail @profile_name = @profile_name,
@recipients = @email_address,
@subject = @subject,
@body = @body,
@file_attachments = @file_attachments
RETURN @retval
END
go
/**************************************************************/
/* SP_VERIFY_NOTIFICATION */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_verify_notification...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_verify_notification')
AND (type = 'P')))
DROP PROCEDURE sp_verify_notification
go
CREATE PROCEDURE sp_verify_notification
@alert_name sysname,
@operator_name sysname,
@notification_method TINYINT,
@alert_id INT OUTPUT,
@operator_id INT OUTPUT
AS
BEGIN
DECLARE @res_valid_range NVARCHAR(100)
SET NOCOUNT ON
SELECT @res_valid_range = FORMATMESSAGE(14208)
-- Remove any leading/trailing spaces from parameters
SELECT @alert_name = LTRIM(RTRIM(@alert_name))
SELECT @operator_name = LTRIM(RTRIM(@operator_name))
-- Check if the AlertName is valid
SELECT @alert_id = id
FROM msdb.dbo.sysalerts
WHERE (name = @alert_name)
IF (@alert_id IS NULL)
BEGIN
RAISERROR(14262, 16, 1, '@alert_name', @alert_name)
RETURN(1) -- Failure
END
-- Check if the OperatorName is valid
SELECT @operator_id = id
FROM msdb.dbo.sysoperators
WHERE (name = @operator_name)
IF (@operator_id IS NULL)
BEGIN
RAISERROR(14262, 16, 1, '@operator_name', @operator_name)
RETURN(1) -- Failure
END
-- If we're at a TSX, we disallow using operator 'MSXOperator'
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.systargetservers)) AND
(@operator_name = N'MSXOperator')
BEGIN
RAISERROR(14251, -1, -1, @operator_name)
RETURN(1) -- Failure
END
-- Check if the NotificationMethod is valid
IF ((@notification_method < 1) OR (@notification_method > 7))
BEGIN
RAISERROR(14266, 16, 1, '@notification_method', @res_valid_range)
RETURN(1) -- Failure
END
RETURN(0) -- Success
END
go
/**************************************************************/
/* SP_ADD_NOTIFICATION */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_notification...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_notification')
AND (type = 'P')))
DROP PROCEDURE sp_add_notification
go
CREATE PROCEDURE sp_add_notification
@alert_name sysname,
@operator_name sysname,
@notification_method TINYINT -- 1 = Email, 2 = Pager, 4 = NetSend, 7 = All
AS
BEGIN
DECLARE @alert_id INT
DECLARE @operator_id INT
DECLARE @notification NVARCHAR(512)
DECLARE @retval INT
DECLARE @old_has_notification INT
DECLARE @new_has_notification INT
DECLARE @res_notification NVARCHAR(100)
SET NOCOUNT ON
SELECT @res_notification = FORMATMESSAGE(14210)
-- Remove any leading/trailing spaces from parameters
SELECT @alert_name = LTRIM(RTRIM(@alert_name))
SELECT @operator_name = LTRIM(RTRIM(@operator_name))
-- Only a sysadmin can do this
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Check if the Notification is valid
EXECUTE @retval = msdb.dbo.sp_verify_notification @alert_name,
@operator_name,
@notification_method,
@alert_id OUTPUT,
@operator_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
-- Check if this notification already exists
-- NOTE: The unique index would catch this, but testing for the problem here lets us
-- control the message.
IF (EXISTS (SELECT *
FROM msdb.dbo.sysnotifications
WHERE (alert_id = @alert_id)
AND (operator_id = @operator_id)))
BEGIN
SELECT @notification = @alert_name + N' / ' + @operator_name
RAISERROR(14261, 16, 1, @res_notification, @notification)
RETURN(1) -- Failure
END
SELECT @old_has_notification = has_notification
FROM msdb.dbo.sysalerts
WHERE (id = @alert_id)
-- Do the INSERT
INSERT INTO msdb.dbo.sysnotifications
(alert_id,
operator_id,
notification_method)
VALUES (@alert_id,
@operator_id,
@notification_method)
SELECT @retval = @@error
SELECT @new_has_notification = has_notification
FROM msdb.dbo.sysalerts
WHERE (id = @alert_id)
-- Notify SQLServerAgent of the change - if any - to has_notifications
IF (@old_has_notification <> @new_has_notification)
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',
@alert_id = @alert_id,
@action_type = N'U'
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_UPDATE_NOTIFICATION */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_notification...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_update_notification')
AND (type = 'P')))
DROP PROCEDURE sp_update_notification
go
CREATE PROCEDURE sp_update_notification
@alert_name sysname,
@operator_name sysname,
@notification_method TINYINT -- 1 = Email, 2 = Pager, 4 = NetSend, 7 = All
AS
BEGIN
DECLARE @alert_id INT
DECLARE @operator_id INT
DECLARE @notification NVARCHAR(512)
DECLARE @retval INT
DECLARE @old_has_notification INT
DECLARE @new_has_notification INT
DECLARE @res_notification NVARCHAR(100)
SET NOCOUNT ON
SELECT @res_notification = FORMATMESSAGE(14210)
-- Remove any leading/trailing spaces from parameters
SELECT @alert_name = LTRIM(RTRIM(@alert_name))
SELECT @operator_name = LTRIM(RTRIM(@operator_name))
-- Only a sysadmin can do this
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Check if the Notification is valid
EXECUTE sp_verify_notification @alert_name,
@operator_name,
@notification_method,
@alert_id OUTPUT,
@operator_id OUTPUT
-- Check if this notification exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysnotifications
WHERE (alert_id = @alert_id)
AND (operator_id = @operator_id)))
BEGIN
SELECT @notification = @alert_name + N' / ' + @operator_name
RAISERROR(14262, 16, 1, @res_notification, @notification)
RETURN(1) -- Failure
END
SELECT @old_has_notification = has_notification
FROM msdb.dbo.sysalerts
WHERE (id = @alert_id)
-- Do the UPDATE
UPDATE msdb.dbo.sysnotifications
SET notification_method = @notification_method
WHERE (alert_id = @alert_id)
AND (operator_id = @operator_id)
SELECT @retval = @@error
SELECT @new_has_notification = has_notification
FROM msdb.dbo.sysalerts
WHERE (id = @alert_id)
-- Notify SQLServerAgent of the change - if any - to has_notifications
IF (@old_has_notification <> @new_has_notification)
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',
@alert_id = @alert_id,
@action_type = N'U'
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_DELETE_NOTIFICATION */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_notification...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_notification')
AND (type = 'P')))
DROP PROCEDURE sp_delete_notification
go
CREATE PROCEDURE sp_delete_notification
@alert_name sysname,
@operator_name sysname
AS
BEGIN
DECLARE @alert_id INT
DECLARE @operator_id INT
DECLARE @ignored TINYINT
DECLARE @notification NVARCHAR(512)
DECLARE @retval INT
DECLARE @old_has_notification INT
DECLARE @new_has_notification INT
DECLARE @res_notification NVARCHAR(100)
SET NOCOUNT ON
SELECT @res_notification = FORMATMESSAGE(14210)
-- Remove any leading/trailing spaces from parameters
SELECT @alert_name = LTRIM(RTRIM(@alert_name))
SELECT @operator_name = LTRIM(RTRIM(@operator_name))
-- Only a sysadmin can do this
IF ((ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) <> 1))
BEGIN
RAISERROR(15003, 16, 1, N'sysadmin')
RETURN(1) -- Failure
END
-- Get the alert and operator ID's
EXECUTE sp_verify_notification @alert_name,
@operator_name,
7, -- A dummy (but valid) value
@alert_id OUTPUT,
@operator_id OUTPUT
-- Check if this notification exists
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysnotifications
WHERE (alert_id = @alert_id)
AND (operator_id = @operator_id)))
BEGIN
SELECT @notification = @alert_name + N' / ' + @operator_name
RAISERROR(14262, 16, 1, @res_notification, @notification)
RETURN(1) -- Failure
END
SELECT @old_has_notification = has_notification
FROM msdb.dbo.sysalerts
WHERE (id = @alert_id)
-- Do the Delete
DELETE FROM msdb.dbo.sysnotifications
WHERE (alert_id = @alert_id)
AND (operator_id = @operator_id)
SELECT @retval = @@error
SELECT @new_has_notification = has_notification
FROM msdb.dbo.sysalerts
WHERE (id = @alert_id)
-- Notify SQLServerAgent of the change - if any - to has_notifications
IF (@old_has_notification <> @new_has_notification)
EXECUTE msdb.dbo.sp_sqlagent_notify @op_type = N'A',
@alert_id = @alert_id,
@action_type = N'U'
RETURN(@retval) -- 0 means success
END
go
/**************************************************************/
/* SP_HELP_NOTIFICATION */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_notification...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_notification')
AND (type = 'P')))
DROP PROCEDURE sp_help_notification
go
CREATE PROCEDURE sp_help_notification
@object_type CHAR(9), -- Either 'ALERTS' (enumerates Alerts for given Operator)
-- or 'OPERATORS' (enumerates Operators for given Alert)
@name sysname, -- Either an Operator Name (if @object_type is 'ALERTS')
-- or an Alert Name (if @object_type is 'OPERATORS')
@enum_type CHAR(10), -- Either 'ALL' (enumerate all objects [eg. all alerts irrespective of whether 'Fred' receives a notification for them])
-- or 'ACTUAL' (enumerate only the associated objects [eg. only the alerts which 'Fred' receives a notification for])
-- or 'TARGET' (enumerate only the objects matching @target_name [eg. a single row showing how 'Fred' is notfied for alert 'Test'])
@notification_method TINYINT, -- Either 1 (Email) - Modifies the result set to only show use_email column
-- or 2 (Pager) - Modifies the result set to only show use_pager column
-- or 4 (NetSend) - Modifies the result set to only show use_netsend column
-- or 7 (All) - Modifies the result set to show all the use_xxx columns
@target_name sysname = NULL -- Either an Alert Name (if @object_type is 'ALERTS')
-- or an Operator Name (if @object_type is 'OPERATORS')
-- NOTE: This parameter is only required if @enum_type is 'TARGET')
AS
BEGIN
DECLARE @id INT -- We use this to store the decode of @name
DECLARE @target_id INT -- We use this to store the decode of @target_name
DECLARE @select_clause NVARCHAR(1024)
DECLARE @from_clause NVARCHAR(512)
DECLARE @where_clause NVARCHAR(512)
DECLARE @res_valid_range NVARCHAR(100)
SET NOCOUNT ON
SELECT @res_valid_range = FORMATMESSAGE(14208)
-- Remove any leading/trailing spaces from parameters
SELECT @object_type = UPPER(LTRIM(RTRIM(@object_type)) collate SQL_Latin1_General_CP1_CS_AS)
SELECT @name = LTRIM(RTRIM(@name))
SELECT @enum_type = UPPER(LTRIM(RTRIM(@enum_type)) collate SQL_Latin1_General_CP1_CS_AS)
SELECT @target_name = LTRIM(RTRIM(@target_name))
-- Turn [nullable] empty string parameters into NULLs
IF (@target_name = N'') SELECT @target_name = NULL
-- Check ObjectType
IF (@object_type NOT IN ('ALERTS', 'OPERATORS'))
BEGIN
RAISERROR(14266, 16, 1, '@object_type', 'ALERTS, OPERATORS')
RETURN(1) -- Failure
END
-- Check AlertName
IF (@object_type = 'OPERATORS') AND
(NOT EXISTS (SELECT *
FROM msdb.dbo.sysalerts
WHERE (name = @name)))
BEGIN
RAISERROR(14262, 16, 1, '@name', @name)
RETURN(1) -- Failure
END
-- Check OperatorName
IF (@object_type = 'ALERTS') AND
(NOT EXISTS (SELECT *
FROM msdb.dbo.sysoperators
WHERE (name = @name)))
BEGIN
RAISERROR(14262, 16, 1, '@name', @name)
RETURN(1) -- Failure
END
-- Check EnumType
IF (@enum_type NOT IN ('ALL', 'ACTUAL', 'TARGET'))
BEGIN
RAISERROR(14266, 16, 1, '@enum_type', 'ALL, ACTUAL, TARGET')
RETURN(1) -- Failure
END
-- Check Notification Method
IF ((@notification_method < 1) OR (@notification_method > 7))
BEGIN
RAISERROR(14266, 16, 1, '@notification_method', @res_valid_range)
RETURN(1) -- Failure
END
-- If EnumType is 'TARGET', check if we have a @TargetName parameter
IF (@enum_type = 'TARGET') AND (@target_name IS NULL)
BEGIN
RAISERROR(14502, 16, 1)
RETURN(1) -- Failure
END
-- If EnumType isn't 'TARGET', we shouldn't have an @target_name parameter
IF (@enum_type <> 'TARGET') AND (@target_name IS NOT NULL)
BEGIN
RAISERROR(14503, 16, 1)
RETURN(1) -- Failure
END
-- Translate the Name into an ID
IF (@object_type = 'ALERTS')
BEGIN
SELECT @id = id
FROM msdb.dbo.sysoperators
WHERE (name = @name)
END
IF (@object_type = 'OPERATORS')
BEGIN
SELECT @id = id
FROM msdb.dbo.sysalerts
WHERE (name = @name)
END
-- Translate the TargetName into a TargetID
IF (@target_name IS NOT NULL)
BEGIN
IF (@object_type = 'OPERATORS')
BEGIN
SELECT @target_id = id
FROM msdb.dbo.sysoperators
WHERE (name = @target_name )
END
IF (@object_type = 'ALERTS')
BEGIN
SELECT @target_id = id
FROM msdb.dbo.sysalerts
WHERE (name = @target_name)
END
IF (@target_id IS NULL) -- IE. the Target Name is invalid
BEGIN
RAISERROR(14262, 16, 1, @object_type, @target_name)
RETURN(1) -- Failure
END
END
-- Ok, the parameters look good so generate the SQL then EXECUTE() it...
-- Generate the 'stub' SELECT clause and the FROM clause
IF (@object_type = 'OPERATORS') -- So we want a list of Operators for the supplied AlertID
BEGIN
SELECT @select_clause = N'SELECT operator_id = o.id, operator_name = o.name, '
IF (@enum_type = 'ALL')
SELECT @from_clause = N'FROM msdb.dbo.sysoperators o LEFT OUTER JOIN msdb.dbo.sysnotifications sn ON (o.id = sn.operator_id) '
ELSE
SELECT @from_clause = N'FROM msdb.dbo.sysoperators o, msdb.dbo.sysnotifications sn '
END
IF (@object_type = 'ALERTS') -- So we want a list of Alerts for the supplied OperatorID
BEGIN
SELECT @select_clause = N'SELECT alert_id = a.id, alert_name = a.name, '
IF (@enum_type = 'ALL')
SELECT @from_clause = N'FROM msdb.dbo.sysalerts a LEFT OUTER JOIN msdb.dbo.sysnotifications sn ON (a.id = sn.alert_id) '
ELSE
SELECT @from_clause = N'FROM msdb.dbo.sysalerts a, msdb.dbo.sysnotifications sn '
END
-- Add the required use_xxx columns to the SELECT clause
IF (@notification_method & 1 = 1)
SELECT @select_clause = @select_clause + N'use_email = ISNULL((sn.notification_method & 1) / POWER(2, 0), 0), '
IF (@notification_method & 2 = 2)
SELECT @select_clause = @select_clause + N'use_pager = ISNULL((sn.notification_method & 2) / POWER(2, 1), 0), '
IF (@notification_method & 4 = 4)
SELECT @select_clause = @select_clause + N'use_netsend = ISNULL((sn.notification_method & 4) / POWER(2, 2), 0), '
-- Remove the trailing comma
SELECT @select_clause = SUBSTRING(@select_clause, 1, (DATALENGTH(@select_clause) / 2) - 2) + N' '
-- Generate the WHERE clause
IF (@object_type = 'OPERATORS')
BEGIN
IF (@enum_type = 'ALL')
SELECT @from_clause = @from_clause + N' AND (sn.alert_id = ' + CONVERT(VARCHAR(10), @id) + N')'
IF (@enum_type = 'ACTUAL')
SELECT @where_clause = N'WHERE (o.id = sn.operator_id) AND (sn.alert_id = ' + CONVERT(VARCHAR(10), @id) + N') AND (sn.notification_method & ' + CONVERT(VARCHAR, @notification_method) + N' <> 0)'
IF (@enum_type = 'TARGET')
SELECT @where_clause = N'WHERE (o.id = sn.operator_id) AND (sn.operator_id = ' + CONVERT(VARCHAR(10), @target_id) + N') AND (sn.alert_id = ' + CONVERT(VARCHAR(10), @id) + N')'
END
IF (@object_type = 'ALERTS')
BEGIN
IF (@enum_type = 'ALL')
SELECT @from_clause = @from_clause + N' AND (sn.operator_id = ' + CONVERT(VARCHAR(10), @id) + N')'
IF (@enum_type = 'ACTUAL')
SELECT @where_clause = N'WHERE (a.id = sn.alert_id) AND (sn.operator_id = ' + CONVERT(VARCHAR(10), @id) + N') AND (sn.notification_method & ' + CONVERT(VARCHAR, @notification_method) + N' <> 0)'
IF (@enum_type = 'TARGET')
SELECT @where_clause = N'WHERE (a.id = sn.alert_id) AND (sn.alert_id = ' + CONVERT(VARCHAR(10), @target_id) + N') AND (sn.operator_id = ' + CONVERT(VARCHAR(10), @id) + N')'
END
-- Add the has_email and has_pager columns to the SELECT clause
IF (@object_type = 'OPERATORS')
BEGIN
SELECT @select_clause = @select_clause + N', has_email = PATINDEX(N''%[^ ]%'', ISNULL(o.email_address, N''''))'
SELECT @select_clause = @select_clause + N', has_pager = PATINDEX(N''%[^ ]%'', ISNULL(o.pager_address, N''''))'
SELECT @select_clause = @select_clause + N', has_netsend = PATINDEX(N''%[^ ]%'', ISNULL(o.netsend_address, N''''))'
END
IF (@object_type = 'ALERTS')
BEGIN
-- NOTE: We return counts so that the UI can detect 'unchecking' the last notification
SELECT @select_clause = @select_clause + N', has_email = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 1) = 1)) '
SELECT @select_clause = @select_clause + N', has_pager = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 2) = 2)) '
SELECT @select_clause = @select_clause + N', has_netsend = (SELECT COUNT(*) FROM sysnotifications WHERE (alert_id = a.id) AND ((notification_method & 4) = 4)) '
END
EXECUTE (@select_clause + @from_clause + @where_clause)
RETURN(@@error) -- 0 means success
END
go
PRINT ''
PRINT 'Creating procedure sp_help_jobactivity...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_help_jobactivity')
AND (type = 'P')))
DROP PROCEDURE sp_help_jobactivity
go
CREATE PROCEDURE sp_help_jobactivity
@job_id UNIQUEIDENTIFIER = NULL, -- If provided should NOT also provide job_name
@job_name sysname = NULL, -- If provided should NOT also provide job_id
@session_id INT = NULL
AS
BEGIN
DECLARE @retval INT
DECLARE @session_id_as_char NVARCHAR(16)
SET NOCOUNT ON
-- Remove any leading/trailing spaces from parameters (except @owner_login_name)
SELECT @job_name = LTRIM(RTRIM(@job_name))
-- Turn [nullable] empty string parameters into NULLs
IF (@job_name = N'') SELECT @job_name = NULL
IF ((@job_id IS NOT NULL) OR (@job_name IS NOT NULL))
BEGIN
EXECUTE @retval = sp_verify_job_identifiers '@job_name',
'@job_id',
@job_name OUTPUT,
@job_id OUTPUT
IF (@retval <> 0)
RETURN(1) -- Failure
END
IF @session_id IS NULL
SELECT TOP(1) @session_id = session_id FROM syssessions ORDER by agent_start_date DESC
ELSE IF NOT EXISTS( SELECT * FROM syssessions WHERE session_id = @session_id)
BEGIN
SELECT @session_id_as_char = CONVERT(NVARCHAR(16), @session_id)
RAISERROR(14262, -1, -1, '@session_id', @session_id_as_char)
RETURN(1) --failure
END
SELECT
ja.session_id,
ja.job_id,
j.name AS job_name,
ja.run_requested_date,
ja.run_requested_source,
ja.queued_date,
ja.start_execution_date,
ja.last_executed_step_id,
ja.last_executed_step_date,
ja.stop_execution_date,
ja.next_scheduled_run_date,
ja.job_history_id,
jh.message,
jh.run_status,
jh.operator_id_emailed,
jh.operator_id_netsent,
jh.operator_id_paged
FROM
(msdb.dbo.sysjobactivity ja LEFT JOIN msdb.dbo.sysjobhistory jh ON ja.job_history_id = jh.instance_id)
join msdb.dbo.sysjobs_view j on ja.job_id = j.job_id
WHERE
(@job_id IS NULL OR ja.job_id = @job_id) AND
ja.session_id = @session_id
RETURN(0)
END
go
/**************************************************************/
/* */
/* T R I G G E R S */
/* */
/**************************************************************/
/**************************************************************/
/* DROP THE OLD 6.x TRIGGERS */
/* [multiple triggers of the same type are allowed in 7.0] */
/**************************************************************/
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'NewOrChangedNotification')
AND (type = 'TR')))
DROP TRIGGER NewOrChangedNotification
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'RemovedNotification')
AND (type = 'TR')))
DROP TRIGGER RemovedNotification
go
/**************************************************************/
/* TRIG_NOTIFICATION_INS_OR_UPD */
/**************************************************************/
PRINT ''
PRINT 'Creating trigger trig_notification_ins_or_upd...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'trig_notification_ins_or_upd')
AND (type = 'TR')))
DROP TRIGGER trig_notification_ins_or_upd
go
CREATE TRIGGER trig_notification_ins_or_upd
ON msdb.dbo.sysnotifications
FOR INSERT,
UPDATE
AS
BEGIN
SET NOCOUNT ON
-- First, throw out 'non-notification' rows
DELETE FROM msdb.dbo.sysnotifications
WHERE (notification_method = 0)
-- Reset the has_notification flag for the affected alerts
UPDATE msdb.dbo.sysalerts
SET has_notification = 0
FROM inserted i,
msdb.dbo.sysalerts sa
WHERE (i.alert_id = sa.id)
-- Update sysalerts.has_notification (for email)
UPDATE msdb.dbo.sysalerts
SET has_notification = has_notification | 1
FROM msdb.dbo.sysalerts sa,
msdb.dbo.sysnotifications sn,
inserted i
WHERE (sa.id = sn.alert_id)
AND (sa.id = i.alert_id)
AND ((sn.notification_method & 1) = 1)
-- Update sysalerts.has_notification (for pager)
UPDATE msdb.dbo.sysalerts
SET has_notification = has_notification | 2
FROM msdb.dbo.sysalerts sa,
msdb.dbo.sysnotifications sn,
inserted i
WHERE (sa.id = sn.alert_id)
AND (sa.id = i.alert_id)
AND ((sn.notification_method & 2) = 2)
-- Update sysalerts.has_notification (for netsend)
UPDATE msdb.dbo.sysalerts
SET has_notification = has_notification | 4
FROM msdb.dbo.sysalerts sa,
msdb.dbo.sysnotifications sn,
inserted i
WHERE (sa.id = sn.alert_id)
AND (sa.id = i.alert_id)
AND ((sn.notification_method & 4) = 4)
END
go
/**************************************************************/
/* TRIG_NOTIFICATION_DELETE */
/**************************************************************/
PRINT ''
PRINT 'Creating trigger trig_notification_delete...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'trig_notification_delete')
AND (type = 'TR')))
DROP TRIGGER trig_notification_delete
go
CREATE TRIGGER trig_notification_delete
ON msdb.dbo.sysnotifications
FOR DELETE
AS
BEGIN
SET NOCOUNT ON
-- Reset the has_notification flag for the affected alerts
UPDATE msdb.dbo.sysalerts
SET has_notification = 0
FROM deleted d,
msdb.dbo.sysalerts sa
WHERE (d.alert_id = sa.id)
-- Update sysalerts.has_notification (for email)
UPDATE msdb.dbo.sysalerts
SET has_notification = has_notification | 1
FROM msdb.dbo.sysalerts sa,
msdb.dbo.sysnotifications sn,
deleted d
WHERE (sa.id = sn.alert_id)
AND (sa.id = d.alert_id)
AND ((sn.notification_method & 1) = 1)
-- Update sysalerts.has_notification (for pager)
UPDATE msdb.dbo.sysalerts
SET has_notification = has_notification | 2
FROM msdb.dbo.sysalerts sa,
msdb.dbo.sysnotifications sn,
deleted d
WHERE (sa.id = sn.alert_id)
AND (sa.id = d.alert_id)
AND ((sn.notification_method & 2) = 2)
-- Update sysalerts.has_notification (for netsend)
UPDATE msdb.dbo.sysalerts
SET has_notification = has_notification | 4
FROM msdb.dbo.sysalerts sa,
msdb.dbo.sysnotifications sn,
deleted d
WHERE (sa.id = sn.alert_id)
AND (sa.id = d.alert_id)
AND ((sn.notification_method & 4) = 4)
END
go
/**************************************************************/
/** **/
/** O B J E C T P E R M I S S I O N S **/
/** **/
/**************************************************************/
--------------------------------------------------------------
-- SQL Agent roles and procs
--------------------------------------------------------------
PRINT ''
PRINT 'Setting object permissions...'
go
-- Create the TargetServers role (for use by target servers when downloading jobs / uploading status)
IF (EXISTS (SELECT *
FROM msdb.dbo.sysusers
WHERE (name = N'TargetServersRole')
AND (issqlrole = 1)))
BEGIN
-- If there are no members in the role, then drop and re-create it
IF ((SELECT COUNT(*)
FROM msdb.dbo.sysusers su,
msdb.dbo.sysmembers sm
WHERE (su.uid = sm.groupuid)
AND (su.name = N'TargetServersRole')
AND (su.issqlrole = 1)) = 0)
BEGIN
EXECUTE msdb.dbo.sp_droprole @rolename = N'TargetServersRole'
EXECUTE msdb.dbo.sp_addrole @rolename = N'TargetServersRole'
END
END
ELSE
EXECUTE msdb.dbo.sp_addrole @rolename = N'TargetServersRole'
-- Create the SQLAgentUserRole role
IF (EXISTS (SELECT *
FROM msdb.dbo.sysusers
WHERE (name = N'SQLAgentUserRole')
AND (issqlrole = 1)))
BEGIN
-- If there are no members in the role, then drop and re-create it
IF ((SELECT COUNT(*)
FROM msdb.dbo.sysusers su,
msdb.dbo.sysmembers sm
WHERE (su.uid = sm.groupuid)
AND (su.name = N'SQLAgentUserRole')
AND (su.issqlrole = 1)) = 0)
BEGIN
EXECUTE msdb.dbo.sp_droprole @rolename = N'SQLAgentUserRole'
EXECUTE msdb.dbo.sp_addrole @rolename = N'SQLAgentUserRole'
END
END
ELSE
EXECUTE msdb.dbo.sp_addrole @rolename = N'SQLAgentUserRole'
-- Create the SQLAgentReaderRole role
IF (EXISTS (SELECT *
FROM msdb.dbo.sysusers
WHERE (name = N'SQLAgentReaderRole')
AND (issqlrole = 1)))
BEGIN
-- If there are no members in the role, then drop and re-create it
IF ((SELECT COUNT(*)
FROM msdb.dbo.sysusers su,
msdb.dbo.sysmembers sm
WHERE (su.uid = sm.groupuid)
AND (su.name = N'SQLAgentReaderRole')
AND (su.issqlrole = 1)) = 0)
BEGIN
EXECUTE msdb.dbo.sp_droprole @rolename = N'SQLAgentReaderRole'
EXECUTE msdb.dbo.sp_addrole @rolename = N'SQLAgentReaderRole'
END
END
ELSE
EXECUTE msdb.dbo.sp_addrole @rolename = N'SQLAgentReaderRole'
-- Create the SQLAgentOperatorRole role
IF (EXISTS (SELECT *
FROM msdb.dbo.sysusers
WHERE (name = N'SQLAgentOperatorRole')
AND (issqlrole = 1)))
BEGIN
-- If there are no members in the role, then drop and re-create it
IF ((SELECT COUNT(*)
FROM msdb.dbo.sysusers su,
msdb.dbo.sysmembers sm
WHERE (su.uid = sm.groupuid)
AND (su.name = N'SQLAgentOperatorRole')
AND (su.issqlrole = 1)) = 0)
BEGIN
EXECUTE msdb.dbo.sp_droprole @rolename = N'SQLAgentOperatorRole'
EXECUTE msdb.dbo.sp_addrole @rolename = N'SQLAgentOperatorRole'
END
END
ELSE
EXECUTE msdb.dbo.sp_addrole @rolename = N'SQLAgentOperatorRole'
-- Add roles to each other.
-- SQLAgentReaderRole is also SQLAgentUserRole
-- SQLAgentOperatorRole is also SQLAgentReaderRole and SQLAgentUserRole
EXECUTE sp_addrolemember @rolename = 'SQLAgentUserRole' ,
@membername = 'SQLAgentReaderRole'
EXECUTE sp_addrolemember @rolename = 'SQLAgentReaderRole' ,
@membername = 'SQLAgentOperatorRole'
go
GRANT EXECUTE ON sp_notify_operator TO SQLAgentUserRole
-- Permissions a non-SA needs to create/update/delete a job
GRANT EXECUTE ON sp_get_sqlagent_properties TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_category TO SQLAgentUserRole
GRANT EXECUTE ON sp_enum_sqlagent_subsystems TO SQLAgentUserRole
GRANT EXECUTE ON sp_add_jobserver TO SQLAgentUserRole
GRANT EXECUTE ON sp_delete_jobserver TO SQLAgentUserRole
GRANT SELECT ON syscategories TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_jobhistory TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_jobhistory_full TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_jobhistory_summary TO SQLAgentUserRole
GRANT EXECUTE ON sp_purge_jobhistory TO SQLAgentOperatorRole
GRANT EXECUTE ON sp_add_jobstep TO SQLAgentUserRole
GRANT EXECUTE ON sp_update_jobstep TO SQLAgentUserRole
GRANT EXECUTE ON sp_delete_jobstep TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_jobstep TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_jobsteplog TO SQLAgentUserRole
GRANT EXECUTE ON sp_delete_jobsteplog TO SQLAgentUserRole
--Schedule related SP's
GRANT EXECUTE ON sp_add_schedule TO SQLAgentUserRole
GRANT EXECUTE ON sp_update_schedule TO SQLAgentUserRole
GRANT EXECUTE ON sp_delete_schedule TO SQLAgentUserRole
GRANT EXECUTE ON sp_attach_schedule TO SQLAgentUserRole
GRANT EXECUTE ON sp_detach_schedule TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_schedule TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_jobcount TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_jobs_in_schedule TO SQLAgentUserRole
GRANT EXECUTE ON sp_add_jobschedule TO SQLAgentUserRole
GRANT EXECUTE ON sp_update_jobschedule TO SQLAgentUserRole
GRANT EXECUTE ON sp_delete_jobschedule TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_jobschedule TO SQLAgentUserRole
GRANT EXECUTE ON sp_add_job TO SQLAgentUserRole
GRANT EXECUTE ON sp_update_job TO SQLAgentUserRole
GRANT EXECUTE ON sp_delete_job TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_job TO SQLAgentUserRole
GRANT EXECUTE ON sp_start_job TO SQLAgentUserRole
GRANT EXECUTE ON sp_stop_job TO SQLAgentUserRole
--alert spocs
GRANT EXECUTE ON sp_help_alert TO SQLAgentOperatorRole
--proxy sprocs
GRANT EXECUTE ON sp_help_proxy TO SQLAgentUserRole
GRANT EXECUTE ON sp_enum_login_for_proxy TO SQLAgentOperatorRole
--other
GRANT EXECUTE ON sp_help_jobserver TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_targetserver TO SQLAgentOperatorRole
GRANT EXECUTE ON sp_help_notification TO SQLAgentOperatorRole
GRANT EXECUTE ON sp_check_for_owned_jobs TO SQLAgentUserRole
GRANT EXECUTE ON sp_check_for_owned_jobsteps TO SQLAgentUserRole
GRANT EXECUTE ON sp_get_jobstep_db_username TO SQLAgentUserRole
GRANT EXECUTE ON sp_get_job_alerts TO SQLAgentUserRole
GRANT EXECUTE ON sp_uniquetaskname TO SQLAgentUserRole
GRANT EXECUTE ON sp_addtask TO SQLAgentUserRole
GRANT EXECUTE ON sp_droptask TO SQLAgentUserRole
GRANT SELECT ON sysjobs_view TO SQLAgentUserRole
GRANT SELECT ON sysschedules_localserver_view TO SQLAgentUserRole
GRANT SELECT ON sysnotifications TO SQLAgentOperatorRole
GRANT SELECT ON sysoperators TO SQLAgentOperatorRole
GRANT SELECT ON sysalerts TO SQLAgentOperatorRole
GRANT SELECT ON sysalerts_performance_counters_view TO SQLAgentOperatorRole
GRANT SELECT ON sysproxies TO TargetServersRole
REVOKE ALL ON systargetservers FROM PUBLIC
REVOKE ALL ON systargetservers_view FROM PUBLIC
REVOKE ALL ON systargetservergroups FROM PUBLIC
REVOKE ALL ON systargetservergroupmembers FROM PUBLIC
REVOKE INSERT, UPDATE, DELETE ON syscategories FROM PUBLIC
REVOKE ALL ON sysalerts FROM PUBLIC
REVOKE ALL ON sysalerts_performance_counters_view FROM PUBLIC
REVOKE ALL ON sysoperators FROM PUBLIC
REVOKE ALL ON sysnotifications FROM PUBLIC
REVOKE ALL ON systargetservers FROM SQLAgentUserRole
REVOKE ALL ON systargetservers_view FROM SQLAgentUserRole
REVOKE ALL ON systargetservergroups FROM SQLAgentUserRole
REVOKE ALL ON systargetservergroupmembers FROM SQLAgentUserRole
REVOKE INSERT, UPDATE, DELETE ON syscategories FROM SQLAgentUserRole
REVOKE ALL ON sysalerts FROM SQLAgentUserRole
REVOKE ALL ON sysalerts_performance_counters_view FROM SQLAgentUserRole
REVOKE ALL ON sysoperators FROM SQLAgentUserRole
REVOKE ALL ON sysnotifications FROM SQLAgentUserRole
--DENY TargetServerRole permission that would allow modifying of jobs
DENY ALL ON sp_add_jobserver TO TargetServersRole
DENY ALL ON sp_delete_jobserver TO TargetServersRole
DENY ALL ON sp_add_jobstep TO TargetServersRole
DENY ALL ON sp_update_jobstep TO TargetServersRole
DENY ALL ON sp_delete_jobstep TO TargetServersRole
DENY ALL ON sp_add_jobschedule TO TargetServersRole
DENY ALL ON sp_update_jobschedule TO TargetServersRole
DENY ALL ON sp_delete_jobschedule TO TargetServersRole
DENY ALL ON sp_add_job TO TargetServersRole
DENY ALL ON sp_update_job TO TargetServersRole
DENY ALL ON sp_delete_job TO TargetServersRole
DENY ALL ON sp_start_job TO TargetServersRole
DENY ALL ON sp_stop_job TO TargetServersRole
DENY ALL ON sp_post_msx_operation TO TargetServersRole
DENY ALL ON sp_addtask TO TargetServersRole
DENY ALL ON sp_droptask TO TargetServersRole
GRANT SELECT, UPDATE, DELETE ON sysdownloadlist TO TargetServersRole
GRANT SELECT, UPDATE ON sysjobservers TO TargetServersRole
GRANT SELECT, UPDATE ON systargetservers TO TargetServersRole
GRANT EXECUTE ON sp_downloaded_row_limiter TO TargetServersRole
GRANT SELECT ON sysjobs TO TargetServersRole
GRANT EXECUTE ON sp_help_jobstep TO TargetServersRole
GRANT EXECUTE ON sp_help_jobschedule TO TargetServersRole
GRANT EXECUTE ON sp_sqlagent_refresh_job TO TargetServersRole
GRANT EXECUTE ON sp_sqlagent_probe_msx TO TargetServersRole
GRANT EXECUTE ON sp_sqlagent_check_msx_version TO TargetServersRole
GRANT EXECUTE ON sp_enlist_tsx TO TargetServersRole
GRANT SELECT ON syssubsystems TO TargetServersRole
GRANT EXECUTE ON sp_help_jobactivity TO SQLAgentUserRole
GRANT EXECUTE ON sp_help_operator TO SQLAgentUserRole
go
/**************************************************************/
/* SP_SEM_ADD_MESSAGE [used by SEM only] */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sem_add_message...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_sem_add_message')
AND (type = 'P')))
DROP PROCEDURE sp_sem_add_message
go
CREATE PROCEDURE sp_sem_add_message
@msgnum INT = NULL,
@severity SMALLINT = NULL,
@msgtext NVARCHAR(255) = NULL,
@lang sysname = NULL, -- Message language name
@with_log VARCHAR(5) = 'FALSE',
@replace VARCHAR(7) = NULL
AS
BEGIN
DECLARE @retval INT
DECLARE @language_name sysname
SET NOCOUNT ON
SET ROWCOUNT 1
SELECT @language_name = name
FROM sys.syslanguages
WHERE msglangid = (SELECT number
FROM master.dbo.spt_values
WHERE (type = 'LNG')
AND (name = @lang))
SET ROWCOUNT 0
SELECT @language_name = ISNULL(@language_name, 'us_english')
EXECUTE @retval = master.dbo.sp_addmessage @msgnum, @severity, @msgtext, @language_name, @with_log, @replace
RETURN(@retval)
END
go
/**************************************************************/
/* SP_SEM_DROP_MESSAGE [used by SEM only] */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_sem_drop_message...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_sem_drop_message')
AND (type = 'P')))
DROP PROCEDURE sp_sem_drop_message
go
CREATE PROCEDURE sp_sem_drop_message
@msgnum int = NULL,
@lang sysname = NULL -- Message language name
AS
BEGIN
DECLARE @retval INT
DECLARE @language_name sysname
SET NOCOUNT ON
SET ROWCOUNT 1
SELECT @language_name = name
FROM sys.syslanguages
WHERE msglangid = (SELECT number
FROM master.dbo.spt_values
WHERE (type = 'LNG')
AND (name = @lang))
SET ROWCOUNT 0
SELECT @language_name = ISNULL(@language_name, 'us_english')
EXECUTE @retval = master.dbo.sp_dropmessage @msgnum, @language_name
RETURN(@retval)
END
go
/**************************************************************/
/* SP_GET_MESSAGE_DESCRIPTION [used by SEM only] */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_get_message_description...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'sp_get_message_description')
AND (type = 'P')))
DROP PROCEDURE sp_get_message_description
go
CREATE PROCEDURE sp_get_message_description
@error INT
AS
BEGIN
IF EXISTS (SELECT * FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = (SELECT msglangid FROM sys.syslanguages WHERE (langid = @@langid))))
SELECT description FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = (SELECT msglangid FROM sys.syslanguages WHERE (langid = @@langid)))
ELSE
SELECT description FROM master.dbo.sysmessages WHERE (error = @error) AND (msglangid = 1033)
END
go
/**************************************************************/
/* SP_HELP_JOBHISTORY_SEM */
/**************************************************************/
use [msdb]
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_jobhistory_sem')
AND (type = 'P')))
DROP PROCEDURE sp_help_jobhistory_sem
go
CREATE PROCEDURE sp_help_jobhistory_sem
@job_id UNIQUEIDENTIFIER,
@job_name sysname,
@step_id INT,
@sql_message_id INT,
@sql_severity INT,
@start_run_date INT,
@end_run_date INT,
@start_run_time INT,
@end_run_time INT,
@minimum_run_duration INT,
@run_status INT,
@minimum_retries INT,
@oldest_first INT,
@server sysname,
@mode VARCHAR(7),
@order_by INT,
@distributed_job_history BIT
AS
-- SQL Enterprise Manager format
IF(@distributed_job_history = 1)
SELECT sj.job_id,
null as step_name,
sjh.last_outcome_message as message,
sjh.last_run_outcome as run_status,
sjh.last_run_date as run_date,
sjh.last_run_time as run_time,
sjh.last_run_duration as run_duration,
null as operator_emailed,
null as operator_netsentname,
null as operator_paged
FROM msdb.dbo.sysjobservers sjh
JOIN msdb.dbo.systargetservers sts ON (sts.server_id = sjh.server_id)
JOIN msdb.dbo.sysjobs_view sj ON(sj.job_id = sjh.job_id)
WHERE
(@job_id = sjh.job_id)
ELSE
SELECT sjh.step_id,
sjh.step_name,
sjh.message,
sjh.run_status,
sjh.run_date,
sjh.run_time,
sjh.run_duration,
operator_emailed = so1.name,
operator_netsent = so2.name,
operator_paged = so3.name
FROM msdb.dbo.sysjobhistory sjh
LEFT OUTER JOIN msdb.dbo.sysoperators so1 ON (sjh.operator_id_emailed = so1.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so2 ON (sjh.operator_id_netsent = so2.id)
LEFT OUTER JOIN msdb.dbo.sysoperators so3 ON (sjh.operator_id_paged = so3.id),
msdb.dbo.sysjobs_view sj
WHERE (sj.job_id = sjh.job_id)
AND (@job_id = sjh.job_id)
ORDER BY (sjh.instance_id * @order_by)
GO
-- Add permissions for this SP.
GRANT EXECUTE ON sp_help_jobhistory_sem TO SQLAgentUserRole
/**************************************************************/
/* */
/* S U P P O R T P R O C E D U R E S */
/* */
/**************************************************************/
/**************************************************************/
/* SP_CONVERT_JOBID_TO_CHAR [used by SEM only] */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_convert_jobid_to_char...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_convert_jobid_to_char')
AND (type = 'P')))
DROP PROCEDURE sp_convert_jobid_to_char
go
CREATE PROCEDURE sp_convert_jobid_to_char
@job_id UNIQUEIDENTIFIER,
@job_id_as_char NVARCHAR(34) OUTPUT -- 34 because of the leading '0x'
AS
BEGIN
DECLARE @job_id_as_binary BINARY(16)
DECLARE @temp NCHAR(8)
DECLARE @counter INT
DECLARE @byte_value INT
DECLARE @high_word INT
DECLARE @low_word INT
DECLARE @high_high_nybble INT
DECLARE @high_low_nybble INT
DECLARE @low_high_nybble INT
DECLARE @low_low_nybble INT
SET NOCOUNT ON
SELECT @job_id_as_binary = CONVERT(BINARY(16), @job_id)
SELECT @temp = CONVERT(NCHAR(8), @job_id_as_binary)
SELECT @job_id_as_char = N''
SELECT @counter = 1
WHILE (@counter <= (DATALENGTH(@temp) / 2))
BEGIN
SELECT @byte_value = CONVERT(INT, CONVERT(BINARY(2), SUBSTRING(@temp, @counter, 1)))
SELECT @high_word = (@byte_value & 0xff00) / 0x100
SELECT @low_word = (@byte_value & 0x00ff)
SELECT @high_high_nybble = (@high_word & 0xff) / 16
SELECT @high_low_nybble = (@high_word & 0xff) % 16
SELECT @low_high_nybble = (@low_word & 0xff) / 16
SELECT @low_low_nybble = (@low_word & 0xff) % 16
IF (@high_high_nybble < 10)
SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @high_high_nybble)
ELSE
SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@high_high_nybble - 10))
IF (@high_low_nybble < 10)
SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @high_low_nybble)
ELSE
SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@high_low_nybble - 10))
IF (@low_high_nybble < 10)
SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @low_high_nybble)
ELSE
SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@low_high_nybble - 10))
IF (@low_low_nybble < 10)
SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('0') + @low_low_nybble)
ELSE
SELECT @job_id_as_char = @job_id_as_char + NCHAR(ASCII('A') + (@low_low_nybble - 10))
SELECT @counter = @counter + 1
END
SELECT @job_id_as_char = N'0x' + LOWER(@job_id_as_char)
END
go
/**************************************************************/
/* */
/* D A T A B A S E M A I L */
/* */
/**************************************************************/
/**************************************************************/
/* */
/* Database Mail Tables */
/* */
/**************************************************************/
----------------------------------------------------------------
-- Database Mail: general configuraiton tables
----------------------------------------------------------------
IF (OBJECT_ID(N'dbo.sysmail_profile', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table sysmail_profile...'
CREATE TABLE dbo.sysmail_profile
(
profile_id int identity not null,
name sysname not null,
description nvarchar(256) null,
last_mod_datetime datetime not null default getdate(),
last_mod_user sysname not null default suser_sname()
CONSTRAINT [SYSMAIL_PROFILE_IDMustBeUnique] PRIMARY KEY(profile_id),
CONSTRAINT [SYSMAIL_PROFILE_NameMustBeUnique] UNIQUE (name)
)
END
ELSE
BEGIN
ALTER TABLE dbo.sysmail_profile ALTER COLUMN description nvarchar(256) null
END
go
IF (OBJECT_ID(N'dbo.sysmail_principalprofile', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table sysmail_principalprofile...'
CREATE TABLE dbo.sysmail_principalprofile
(
profile_id int not null references sysmail_profile(profile_id) on delete cascade,
principal_sid varbinary(85) not null, -- sys.database_principals.sid
is_default bit not null default 0,
last_mod_datetime datetime not null default getdate(),
last_mod_user sysname not null default suser_sname()
CONSTRAINT [SYSMAIL_PRINCIPALPROFILE_ProfilePrincipalMustBeUnique] PRIMARY KEY(profile_id,principal_sid),
)
END
ELSE
BEGIN
-- add principal_sid column
IF NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='principal_sid' and id =
(SELECT OBJECT_ID(N'dbo.sysmail_principalprofile', 'U')))
BEGIN
ALTER TABLE dbo.sysmail_principalprofile ADD principal_sid varbinary(85) not null default 0xFFFF
END
END
go
IF (OBJECT_ID(N'dbo.sysmail_account', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table sysmail_account...'
CREATE TABLE dbo.sysmail_account
(
account_id int identity not null,
name sysname not null,
description nvarchar(256) null,
email_address nvarchar(128) not null,
display_name nvarchar(128) null,
replyto_address nvarchar(128) null,
last_mod_datetime datetime not null default getdate(),
last_mod_user sysname not null default suser_sname()
CONSTRAINT [SYSMAIL_ACCOUNT_IDMustBeUnique] PRIMARY KEY(account_id),
CONSTRAINT [SYSMAIL_ACCOUNT_NameMustBeUnique] UNIQUE (name)
)
END
ELSE
BEGIN
ALTER TABLE dbo.sysmail_account ALTER COLUMN description nvarchar(256) null
ALTER TABLE dbo.sysmail_account ALTER COLUMN display_name nvarchar(128) null
ALTER TABLE dbo.sysmail_account ALTER COLUMN replyto_address nvarchar(128) null
END
go
IF (OBJECT_ID(N'dbo.sysmail_profileaccount', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table sysmail_profileaccount...'
CREATE TABLE dbo.sysmail_profileaccount
(
profile_id int not null,
account_id int not null references sysmail_account(account_id) on delete cascade,
sequence_number int null,
last_mod_datetime datetime not null default getdate(),
last_mod_user sysname not null default suser_sname()
CONSTRAINT [SYSMAIL_ACCOUNT_ProfileAccountMustBeUnique] PRIMARY KEY(profile_id,account_id)
)
END
ELSE
BEGIN
ALTER TABLE dbo.sysmail_profileaccount ALTER COLUMN sequence_number int null
END
go
IF (OBJECT_ID(N'dbo.sysmail_servertype', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table sysmail_servertype...'
CREATE TABLE dbo.sysmail_servertype
(
servertype sysname not null,
is_incoming bit not null default 0,
is_outgoing bit not null default 1,
last_mod_datetime datetime not null default getdate(),
last_mod_user sysname not null default suser_sname()
CONSTRAINT [SYSMAIL_SERVERTYPE_TypeMustBeUnique] PRIMARY KEY(servertype),
)
END
go
IF (OBJECT_ID(N'dbo.sysmail_server', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table sysmail_server...'
CREATE TABLE dbo.sysmail_server
(
account_id int not null references sysmail_account(account_id) on delete cascade,
servertype sysname not null references sysmail_servertype(servertype),
servername sysname not null,
port int not null default 25,
username nvarchar(128) null,
credential_id int null,
use_default_credentials bit not null default 0,
enable_ssl bit not null default 0,
flags int not null default 0,
timeout int NULL,
last_mod_datetime datetime not null default getdate(),
last_mod_user sysname not null default suser_sname()
CONSTRAINT [SYSMAIL_ACCOUNT_AccountServerTypeMustBeUnique] PRIMARY KEY(account_id,servertype)
)
END
ELSE -- check if we need to add missing columns
BEGIN
IF NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='use_default_credentials' and id =
(SELECT OBJECT_ID(N'dbo.sysmail_server', 'U')))
BEGIN
ALTER TABLE dbo.sysmail_server ADD use_default_credentials bit not null default 0
END
IF NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='enable_ssl' and id =
(SELECT OBJECT_ID(N'dbo.sysmail_server', 'U')))
BEGIN
ALTER TABLE dbo.sysmail_server ADD enable_ssl bit not null default 0
END
IF NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='flags' and id =
(SELECT OBJECT_ID(N'dbo.sysmail_server', 'U')))
BEGIN
ALTER TABLE dbo.sysmail_server ADD flags int not null default 0
END
IF NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='timeout' and id =
(SELECT OBJECT_ID(N'dbo.sysmail_server', 'U')))
BEGIN
ALTER TABLE dbo.sysmail_server ADD timeout int NULL
END
END
go
IF (OBJECT_ID(N'dbo.sysmail_configuration', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table sysmail_configuration...'
CREATE TABLE dbo.sysmail_configuration
(
paramname nvarchar(256) not null,
paramvalue nvarchar(256) null,
description nvarchar(256) null,
last_mod_datetime datetime not null default getdate(),
last_mod_user sysname not null default suser_sname()
CONSTRAINT [SYSMAIL_CONFIGURATION_ParamnameMustBeUnique] PRIMARY KEY(paramname)
)
END
ELSE
BEGIN
ALTER TABLE dbo.sysmail_configuration ALTER COLUMN paramvalue nvarchar(256) null
ALTER TABLE dbo.sysmail_configuration ALTER COLUMN description nvarchar(256) null
END
go
-- populate default configuration settings
DECLARE @description NVARCHAR(256)
SELECT @description = FORMATMESSAGE(14642)
IF NOT EXISTS(SELECT * FROM dbo.sysmail_configuration WHERE paramname = N'DefaultAttachmentEncoding')
INSERT INTO dbo.sysmail_configuration (paramname,paramvalue,description) VALUES (N'DefaultAttachmentEncoding', N'MIME', @description)
ELSE
UPDATE dbo.sysmail_configuration SET description = @description WHERE paramname = N'DefaultAttachmentEncoding'
-- maximum size of an Database Mail atachement 1MB
SELECT @description = FORMATMESSAGE(14644)
IF NOT EXISTS(SELECT * FROM dbo.sysmail_configuration WHERE paramname = N'MaxFileSize')
INSERT INTO dbo.sysmail_configuration (paramname,paramvalue,description) VALUES (N'MaxFileSize', N'1000000', @description)
ELSE
UPDATE dbo.sysmail_configuration SET description = @description WHERE paramname = N'MaxFileSize'
SELECT @description = FORMATMESSAGE(14645)
IF NOT EXISTS(SELECT * FROM dbo.sysmail_configuration WHERE paramname = N'ProhibitedExtensions')
INSERT INTO dbo.sysmail_configuration (paramname,paramvalue,description) VALUES (N'ProhibitedExtensions', N'exe,dll,vbs,js', @description)
ELSE
UPDATE dbo.sysmail_configuration SET description = @description WHERE paramname = N'ProhibitedExtensions'
SELECT @description = FORMATMESSAGE(14646)
IF NOT EXISTS(SELECT * FROM dbo.sysmail_configuration WHERE paramname = N'AccountRetryAttempts')
INSERT INTO dbo.sysmail_configuration (paramname,paramvalue,description) VALUES (N'AccountRetryAttempts', N'1', @description)
ELSE
UPDATE dbo.sysmail_configuration SET description = @description WHERE paramname = N'AccountRetryAttempts'
SELECT @description = FORMATMESSAGE(14647)
IF NOT EXISTS(SELECT * FROM dbo.sysmail_configuration WHERE paramname = N'AccountRetryDelay')
INSERT INTO dbo.sysmail_configuration (paramname,paramvalue,description) VALUES (N'AccountRetryDelay', N'60', @description)
ELSE
UPDATE dbo.sysmail_configuration SET description = @description WHERE paramname = N'AccountRetryDelay'
SELECT @description = FORMATMESSAGE(14648)
IF NOT EXISTS(SELECT * FROM dbo.sysmail_configuration WHERE paramname = N'DatabaseMailExeMinimumLifeTime')
INSERT INTO dbo.sysmail_configuration (paramname,paramvalue,description) VALUES (N'DatabaseMailExeMinimumLifeTime', N'600', @description)
ELSE
UPDATE dbo.sysmail_configuration SET description = @description WHERE paramname = N'DatabaseMailExeMinimumLifeTime'
-- component logging level: normal - 1, extended - 2 (default), verbose - 3
SELECT @description = FORMATMESSAGE(14664)
IF NOT EXISTS(SELECT * FROM dbo.sysmail_configuration WHERE paramname = N'LoggingLevel')
INSERT INTO dbo.sysmail_configuration (paramname,paramvalue,description) VALUES (N'LoggingLevel', N'2', @description)
ELSE
UPDATE dbo.sysmail_configuration SET description = @description WHERE paramname = N'LoggingLevel'
go
----------------------------------------------------------------
-- Database Mail: mail host database specific tables
----------------------------------------------------------------
-----------------------------------------------------------
-- TABLE sysmail_mailitems
-----------------------------------------------------------
-- sysmail_mailitems : Contains one row for each mail sent using sp_send_dbmail.
-- Contains mails that are waiting to be sent and the sent mail.
-- sent_status determines its status
--
-- mailitem_id : Id for the row. Auto-generated.
-- profile_id : ID of profile to use to send the mail.
-- recipients : People on the To list.
-- copy_recipients : People on the Cc list.
-- blind_copy_recipients : People on the Bcc list.
-- subject : Subject of the email.
-- body : Body of the email.
-- body_format : Body format. 0 (Text), 1(Html)
-- importance : Importance of the email:
-- 0(Low), 1(Normal), 2(High).
-- sensitivity : Sensitivity of the email:
-- 0(Normal), 1(Personal), 2(Private), 3(Confidential).
-- attachment_encoding : Encoding to use for mail and attachments:
-- 0(MIME), 1(UUEncode), 2(BINHEX), 3(S/MIME).
-- query : SQL query that was executed in this mail
-- execute_query_database : The database to execute the query in
-- attach_query_result_as_file : Option for attaching the query result
-- as a file instead of in the mail body
-- query_result_header : Option for including query result column headers
-- query_result_width : The query result overall width in characters
-- query_result_separator : The query result column separaror character
-- exclude_query_output : Option for supressing query output being returned to
-- the client that is sending the mail
-- append_query_error : Option for appending query error messages to the mail item
-- send_request_date : Date this mail item was created
-- send_request_user : The user that created this mail item
-- sent_account_id : The account_id that was used to send this mail item
-- sent_status : The current status of the mail item.
-- : 0(PendingSend), 1(SendSuccessful), 2(SendFailed), 3(AttemptingSendRetry)
-- sent_date : Date the mail item was sent or failed to be sent
-- from_adress : Optional override of the from header.
-- reply_to : Optional setting of the reply-to header.
-----------------------------------------------------------
IF(OBJECT_ID('dbo.sysmail_mailitems', 'U') IS NULL)
BEGIN
PRINT 'Creating TABLE sysmail_mailitems'
CREATE TABLE sysmail_mailitems
(
mailitem_id INT IDENTITY(1,1) NOT NULL,
profile_id INT NOT NULL,
recipients VARCHAR(MAX) NULL,
copy_recipients VARCHAR(MAX) NULL,
blind_copy_recipients VARCHAR(MAX) NULL,
subject NVARCHAR(255) NULL,
from_address VARCHAR(MAX) NULL,
reply_to VARCHAR(MAX) NULL,
body NVARCHAR(MAX) NULL,
body_format VARCHAR(20) NULL,
importance VARCHAR(6) NULL,
sensitivity VARCHAR(12) NULL,
file_attachments NVARCHAR(MAX) NULL,
attachment_encoding VARCHAR(20) NULL,
query NVARCHAR(MAX) NULL,
execute_query_database sysname NULL,
attach_query_result_as_file BIT NULL,
query_result_header BIT NULL,
query_result_width INT NULL,
query_result_separator CHAR(1) NULL,
exclude_query_output BIT NULL,
append_query_error BIT NULL,
send_request_date DATETIME NOT NULL DEFAULT GETDATE(),
send_request_user sysname NOT NULL DEFAULT SUSER_SNAME(),
sent_account_id INT NULL,
sent_status TINYINT NULL DEFAULT 0,
sent_date DATETIME NULL,
last_mod_date DATETIME NOT NULL DEFAULT GETDATE(),
last_mod_user sysname NOT NULL DEFAULT SUSER_SNAME(),
CONSTRAINT [sysmail_mailitems_id_MustBeUnique] PRIMARY KEY(mailitem_id),
CONSTRAINT [sysmail_OutMailMustHaveAtleastOneRecipient]
CHECK (NOT (recipients IS NULL AND copy_recipients IS NULL AND blind_copy_recipients IS NULL)),
CONSTRAINT [sysmail_OutMailRecipientCannotBeEmpty]
CHECK (DATALENGTH(ISNULL(recipients, '')) +
DATALENGTH(ISNULL(copy_recipients, '')) +
DATALENGTH(ISNULL(blind_copy_recipients, '')) <> 0),
CONSTRAINT [sysmail_OutMailAttachmentEncodingMustBeValid]
CHECK (attachment_encoding IN ('MIME', 'S/MIME', 'BINHEX', 'UUENCODE')),
CONSTRAINT [sysmail_OutMailImportanceMustBeValid]
CHECK (importance IN ('LOW', 'NORMAL', 'HIGH')),
CONSTRAINT [sysmail_OutMailSensitivityMustBeValid]
CHECK (sensitivity IN('NORMAL', 'PERSONAL', 'PRIVATE', 'CONFIDENTIAL'))
)
END
ELSE
BEGIN
-- handle schema upgrade for sysmail_mailitems table
IF NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='profile_id' and id =
(SELECT OBJECT_ID(N'dbo.sysmail_mailitems', 'U')))
BEGIN
ALTER TABLE dbo.sysmail_mailitems ADD profile_id INT NOT NULL DEFAULT -1
END
IF NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='from_address' and id =
(SELECT OBJECT_ID(N'dbo.sysmail_mailitems', 'U')))
BEGIN
ALTER TABLE dbo.sysmail_mailitems ADD from_address VARCHAR(MAX) NULL
ALTER TABLE dbo.sysmail_mailitems ADD reply_to VARCHAR(MAX) NULL
END
END
GO
/**************************************************************/
/* sysmail_allitems */
/**************************************************************/
PRINT ''
PRINT 'Creating view sysmail_allitems...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmail_allitems')
AND (type = 'V')))
DROP VIEW sysmail_allitems
go
CREATE VIEW sysmail_allitems
AS
SELECT mailitem_id,
profile_id,
recipients,
copy_recipients,
blind_copy_recipients,
subject,
body,
body_format,
importance,
sensitivity,
file_attachments,
attachment_encoding,
query,
execute_query_database,
attach_query_result_as_file,
query_result_header,
query_result_width,
query_result_separator,
exclude_query_output,
append_query_error,
send_request_date,
send_request_user,
sent_account_id,
CASE sent_status
WHEN 0 THEN 'unsent'
WHEN 1 THEN 'sent'
WHEN 3 THEN 'retrying'
ELSE 'failed'
END as sent_status,
sent_date,
last_mod_date,
last_mod_user
FROM msdb.dbo.sysmail_mailitems
WHERE (send_request_user = SUSER_SNAME()) OR (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
GO
/**************************************************************/
/* sysmail_sentitems */
/**************************************************************/
PRINT ''
PRINT 'Creating view sysmail_sentitems...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmail_sentitems')
AND (type = 'V')))
DROP VIEW sysmail_sentitems
go
CREATE VIEW sysmail_sentitems
AS
SELECT * FROM msdb.dbo.sysmail_allitems WHERE sent_status = 'sent'
go
/**************************************************************/
/* sysmail_unsentitems */
/**************************************************************/
PRINT ''
PRINT 'Creating view sysmail_unsentitems...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmail_unsentitems')
AND (type = 'V')))
DROP VIEW sysmail_unsentitems
go
CREATE VIEW sysmail_unsentitems
AS
SELECT * FROM msdb.dbo.sysmail_allitems WHERE (sent_status = 'unsent' OR sent_status = 'retrying')
go
/**************************************************************/
/* sysmail_faileditems */
/**************************************************************/
PRINT ''
PRINT 'Creating view sysmail_faileditems...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmail_faileditems')
AND (type = 'V')))
DROP VIEW sysmail_faileditems
go
CREATE VIEW sysmail_faileditems
AS
SELECT * FROM msdb.dbo.sysmail_allitems WHERE sent_status = 'failed'
go
-----------------------------------------------------------
-- procedure sysmail_delete_mailitems_sp
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sysmail_delete_mailitems_sp', 'P') IS NULL
DROP PROCEDURE dbo.sysmail_delete_mailitems_sp
GO
-----
PRINT 'Creating sysmail_delete_mailitems_sp'
-----
GO
CREATE PROCEDURE sysmail_delete_mailitems_sp
@sent_before DATETIME = NULL, -- sent before
@sent_status varchar(8) = NULL -- sent status
AS
BEGIN
SET @sent_status = LTRIM(RTRIM(@sent_status))
IF @sent_status = '' SET @sent_status = NULL
IF ( (@sent_status IS NOT NULL) AND
(LOWER(@sent_status collate SQL_Latin1_General_CP1_CS_AS) NOT IN ( 'unsent', 'sent', 'failed', 'retrying') ) )
BEGIN
RAISERROR(14266, -1, -1, '@sent_status', 'unsent, sent, failed, retrying')
RETURN(1) -- Failure
END
IF ( @sent_before IS NULL AND @sent_status IS NULL )
BEGIN
RAISERROR(14608, -1, -1, '@sent_before', '@sent_status')
RETURN(1) -- Failure
END
DELETE FROM msdb.dbo.sysmail_allitems
WHERE
((@sent_before IS NULL) OR ( send_request_date < @sent_before))
AND ((@sent_status IS NULL) OR (sent_status = @sent_status))
DECLARE @localmessage nvarchar(255)
SET @localmessage = FORMATMESSAGE(14665, SUSER_SNAME(), @@ROWCOUNT)
exec msdb.dbo.sysmail_logmailevent_sp @event_type=1, @description=@localmessage
END
GO
-----------------------------------------------------------
-- TABLE sysmail_attachments
-----------------------------------------------------------
-- sysmail_attachments : Contains mail item attachments
--
-- attachment_id : Id for the row. Auto-generated
-- mailitem_id : Optional key to the mail items that this entry is a about
-- filename : The filename of the attachment
-- filesize : Size of the file
-- encoded_attachment : The file data encoded in base64
----------------------------------------------------------------
IF (OBJECT_ID('dbo.sysmail_attachments', 'U') IS NULL)
BEGIN
PRINT 'Creating TABLE sysmail_attachments'
CREATE TABLE sysmail_attachments
(
attachment_id INT IDENTITY(1, 1) NOT NULL,
mailitem_id INT NOT NULL CONSTRAINT
FK_sysmail_mailitems_mailitem_id
FOREIGN KEY (mailitem_id) REFERENCES sysmail_mailitems(mailitem_id) ON DELETE CASCADE,
filename NVARCHAR(260) NOT NULL,
filesize INT NOT NULL,
attachment VARBINARY(MAX) NULL,
last_mod_date DATETIME NOT NULL DEFAULT GETDATE(),
last_mod_user sysname NOT NULL DEFAULT SUSER_SNAME()
)
END
ELSE
BEGIN
BEGIN TRAN
-- remove any old constraint
declare @fkName sysname
DECLARE @sql NVARCHAR(4000)
SELECT @fkName = cstr.name
FROM
sys.tables AS tbl
INNER JOIN sys.foreign_keys AS cstr ON cstr.parent_object_id=tbl.object_id
LEFT OUTER JOIN sys.indexes AS ki ON ki.index_id = cstr.key_index_id and ki.object_id = cstr.referenced_object_id
INNER JOIN sys.tables rtbl ON rtbl.object_id = cstr.referenced_object_id
WHERE
tbl.name=N'sysmail_attachments'
IF (@fkName IS NOT NULL)
BEGIN
select @sql = N'ALTER TABLE sysmail_attachments DROP CONSTRAINT ' + QUOTENAME(@fkName)
EXEC (@sql)
END
ALTER TABLE sysmail_attachments ADD CONSTRAINT FK_sysmail_mailitems_mailitem_id
FOREIGN KEY (mailitem_id) REFERENCES sysmail_mailitems(mailitem_id) ON DELETE CASCADE
COMMIT
END
GO
/**************************************************************/
/* sysmail_mailattachments */
/**************************************************************/
PRINT ''
PRINT 'Creating view sysmail_mailattachments...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmail_mailattachments')
AND (type = 'V')))
DROP VIEW sysmail_mailattachments
go
CREATE VIEW sysmail_mailattachments
AS
SELECT attachment_id,
sa.mailitem_id,
filename,
filesize,
attachment,
sa.last_mod_date,
sa.last_mod_user
FROM msdb.dbo.sysmail_attachments sa
JOIN msdb.dbo.sysmail_mailitems sm ON sa.mailitem_id = sm.mailitem_id
WHERE (sm.send_request_user = SUSER_SNAME()) OR (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1)
GO
-----------------------------------------------------------
-- TABLE sysmail_send_retries
-----------------------------------------------------------
-- sysmail_send_retries : Contains send mail retry history
--
-- conversation_handle : The conversation handle that initiated the retry
-- mailitem_id : Optional key to the mail items that this entry is a about
-- send_attempts : The current number of send attempts
-- last_send_attempt_date : date of the last send attempt
----------------------------------------------------------------
IF (OBJECT_ID('dbo.sysmail_send_retries', 'U') IS NULL)
BEGIN
PRINT 'Creating TABLE sysmail_send_retries'
CREATE TABLE sysmail_send_retries
(
conversation_handle uniqueidentifier PRIMARY KEY NOT NULL,
mailitem_id INT NOT NULL CONSTRAINT FK_mailitems_mailitem_id
FOREIGN KEY (mailitem_id) REFERENCES sysmail_mailitems(mailitem_id) ON DELETE CASCADE,
send_attempts INT NOT NULL DEFAULT 1,
last_send_attempt_date DATETIME NOT NULL DEFAULT GETDATE()
)
END
ELSE
BEGIN
BEGIN TRAN
-- remove any old constraint
declare @fkName sysname
DECLARE @sql NVARCHAR(4000)
SELECT @fkName = cstr.name
FROM
sys.tables AS tbl
INNER JOIN sys.foreign_keys AS cstr ON cstr.parent_object_id=tbl.object_id
LEFT OUTER JOIN sys.indexes AS ki ON ki.index_id = cstr.key_index_id and ki.object_id = cstr.referenced_object_id
INNER JOIN sys.tables rtbl ON rtbl.object_id = cstr.referenced_object_id
WHERE
tbl.name=N'sysmail_send_retries'
IF (@fkName IS NOT NULL)
BEGIN
SET @sql = N'ALTER TABLE sysmail_send_retries DROP CONSTRAINT ' + @fkName
EXECUTE (@sql)
END
ALTER TABLE sysmail_send_retries ADD CONSTRAINT FK_mailitems_mailitem_id
FOREIGN KEY (mailitem_id) REFERENCES sysmail_mailitems(mailitem_id) ON DELETE CASCADE
COMMIT
END
GO
-----------------------------------------------------------
-- TABLE sysmail_log
-----------------------------------------------------------
-- sysmail_log : Contains error and event logging
--
-- log_id : Id for the row. Auto-generated.
-- event_type : The event type for this record
-- 0(Success), 1(information), 2(Warning), 3(error)
-- log_date : Create date of this log entry
-- description : The text description of this entry
-- process_id : The DatabaseMail (exe) process id that added this entry
-- mailitem_id : Optional key to the mail items that this entry is a about
-- account_id : Optional account_id hat this entry is a about
----------------------------------------------------------------
IF (OBJECT_ID('dbo.sysmail_log', 'U') IS NULL)
BEGIN
PRINT 'Creating TABLE sysmail_log'
CREATE TABLE sysmail_log
(
log_id INT IDENTITY(1, 1) NOT NULL,
event_type INT NOT NULL,
log_date DATETIME NOT NULL DEFAULT GETDATE(),
description NVARCHAR(max) NULL,
process_id INT NULL,
mailitem_id INT NULL,
account_id INT NULL,
last_mod_date DATETIME NOT NULL DEFAULT GETDATE(),
last_mod_user sysname NOT NULL DEFAULT SUSER_SNAME(),
CONSTRAINT [sysmail_log_id_MustBeUnique] PRIMARY KEY(log_id),
)
END
ELSE
BEGIN
-- remove any old constraint
declare @fkName sysname
DECLARE @sql NVARCHAR(4000)
SELECT @fkName = cstr.name
FROM
sys.tables AS tbl
INNER JOIN sys.foreign_keys AS cstr ON cstr.parent_object_id=tbl.object_id
LEFT OUTER JOIN sys.indexes AS ki ON ki.index_id = cstr.key_index_id and ki.object_id = cstr.referenced_object_id
INNER JOIN sys.tables rtbl ON rtbl.object_id = cstr.referenced_object_id
WHERE
tbl.name=N'sysmail_log'
IF (@fkName IS NOT NULL)
begin
select @sql = N'ALTER TABLE sysmail_log DROP CONSTRAINT ' + QUOTENAME(@fkName)
EXEC (@sql)
end
END
GO
/**************************************************************/
/* sysmail_event_log */
/**************************************************************/
use msdb
go
PRINT ''
PRINT 'Creating view sysmail_event_log...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmail_event_log')
AND (type = 'V')))
DROP VIEW sysmail_event_log
go
CREATE VIEW sysmail_event_log
AS
SELECT log_id,
CASE event_type
WHEN 0 THEN 'success'
WHEN 1 THEN 'information'
WHEN 2 THEN 'warning'
ELSE 'error'
END as event_type,
log_date,
description,
process_id,
sl.mailitem_id,
account_id,
sl.last_mod_date,
sl.last_mod_user
FROM [dbo].[sysmail_log] sl
WHERE (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1) OR
(EXISTS ( SELECT mailitem_id FROM [dbo].[sysmail_allitems] ai WHERE sl.mailitem_id = ai.mailitem_id ))
GO
-----------------------------------------------------------
-- procedure sysmail_delete_log_sp
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sysmail_delete_log_sp', 'P') IS NULL
DROP PROCEDURE dbo.sysmail_delete_log_sp
GO
-----
PRINT 'Creating sysmail_delete_log_sp'
-----
GO
CREATE PROCEDURE sysmail_delete_log_sp
@logged_before DATETIME = NULL,
@event_type varchar(15) = NULL
AS
BEGIN
SET @event_type = LTRIM(RTRIM(@event_type))
IF @event_type = '' SET @event_type = NULL
DECLARE @event_type_numeric INT
IF ( (@event_type IS NOT NULL) AND
(LOWER(@event_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ( 'success', 'warning', 'error', 'information' ) ) )
BEGIN
RAISERROR(14266, -1, -1, '@event_type', 'success, warning, error, information')
RETURN(1) -- Failure
END
IF ( @event_type IS NOT NULL)
BEGIN
SET @event_type_numeric = ( SELECT CASE
WHEN @event_type = 'success' THEN 0
WHEN @event_type = 'information' THEN 1
WHEN @event_type = 'warning' THEN 2
ELSE 3 END
)
END
ELSE
SET @event_type_numeric = NULL
DELETE FROM msdb.dbo.sysmail_log
WHERE
((@logged_before IS NULL) OR ( log_date < @logged_before))
AND ((@event_type_numeric IS NULL) OR (@event_type_numeric = event_type))
END
GO
-----------------------------------------------------------
-- sysmail_query_transfer : Table used to transfer data between a helper xp's and the calling sp's.
-- Rows are created and deleted in the context of each call
--
-- uid : guid for the row. Generated by the user
-- text_data : Attachment data in binary form
----------------------------------------------------------------
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmail_query_transfer')
AND (type = 'U')))
BEGIN
PRINT 'Creating TABLE sysmail_query_transfer'
CREATE TABLE sysmail_query_transfer
(
uid uniqueidentifier NOT NULL PRIMARY KEY,
text_data NVARCHAR(max) NULL,
create_date DATETIME NOT NULL DEFAULT GETDATE()
)
END
GO
-----------------------------------------------------------
-- sysmail_attachments_transfer : Table used to transfer data between a helper xp's
-- and the calling sp's. Rows are created and deleted
-- in the context of each call
--
-- uid : guid for the row. Generated by the user
-- filename : Attachment file name
-- filesize : Attachment file size in bytes
-- attachment : Attachment data in binary form
----------------------------------------------------------------
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmail_attachments_transfer')
AND (type = 'U')))
BEGIN
PRINT 'Creating TABLE sysmail_attachments_transfer'
CREATE TABLE sysmail_attachments_transfer
(
transfer_id INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
uid uniqueidentifier NOT NULL,
filename NVARCHAR(260) NOT NULL,
filesize INT NOT NULL,
attachment VARBINARY(MAX) NULL,
create_date DATETIME NOT NULL DEFAULT GETDATE()
)
END
GO
/*************************************************************************/
/* */
/* Database Mail Triggers */
/* */
/*************************************************************************/
------------------------------------------------------------
-- Database Mail: triggers on general configuration tables
------------------------------------------------------------
PRINT ''
PRINT 'Creating trigger trig_sysmail_profile...'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'trig_sysmail_profile')
AND (type = 'TR')))
DROP TRIGGER dbo.trig_sysmail_profile
go
CREATE TRIGGER trig_sysmail_profile
ON msdb.dbo.sysmail_profile
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
IF (TRIGGER_NESTLEVEL( OBJECT_ID('dbo.trig_sysmail_profile'), 'AFTER' , 'DML' ) <= 1)
BEGIN
UPDATE msdb.dbo.sysmail_profile
SET last_mod_datetime = getdate(),last_mod_user = suser_sname()
FROM sysmail_profile p, inserted i
WHERE p.profile_id = i.profile_id
END
END
go
PRINT ''
PRINT 'Creating trigger trig_principalprofile...'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'trig_principalprofile')
AND (type = 'TR')))
DROP TRIGGER dbo.trig_principalprofile
go
CREATE TRIGGER trig_principalprofile
ON msdb.dbo.sysmail_principalprofile
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
IF (TRIGGER_NESTLEVEL( OBJECT_ID('dbo.trig_principalprofile'), 'AFTER' , 'DML' ) <= 1)
BEGIN
UPDATE msdb.dbo.sysmail_principalprofile
SET last_mod_datetime = getdate(),last_mod_user = suser_sname()
FROM sysmail_principalprofile p, inserted i
WHERE p.profile_id = i.profile_id and p.principal_sid = i.principal_sid
END
END
go
PRINT ''
PRINT 'Creating trigger trig_sysmail_account...'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'trig_sysmail_account')
AND (type = 'TR')))
DROP TRIGGER dbo.trig_sysmail_account
go
CREATE TRIGGER trig_sysmail_account
ON msdb.dbo.sysmail_account
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
IF (TRIGGER_NESTLEVEL( OBJECT_ID('dbo.trig_sysmail_account'), 'AFTER' , 'DML' ) <= 1)
BEGIN
UPDATE msdb.dbo.sysmail_account
SET last_mod_datetime = getdate(),last_mod_user = suser_sname()
FROM sysmail_account a, inserted i
WHERE a.account_id = i.account_id
END
END
go
PRINT ''
PRINT 'Creating trigger trig_sysmail_profileaccount...'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'trig_sysmail_profileaccount')
AND (type = 'TR')))
DROP TRIGGER dbo.trig_sysmail_profileaccount
go
CREATE TRIGGER trig_sysmail_profileaccount
ON msdb.dbo.sysmail_profileaccount
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
IF (TRIGGER_NESTLEVEL( OBJECT_ID('dbo.trig_sysmail_profileaccount'), 'AFTER' , 'DML' ) <= 1)
BEGIN
UPDATE msdb.dbo.sysmail_profileaccount
SET last_mod_datetime = getdate(),last_mod_user = suser_sname()
FROM sysmail_profileaccount p, inserted i
WHERE p.profile_id = i.profile_id and p.account_id = i.account_id
END
END
go
PRINT ''
PRINT 'Creating trigger trig_sysmail_profile_delete...'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'trig_sysmail_profile_delete')
AND (type = 'TR')))
DROP TRIGGER dbo.trig_sysmail_profile_delete
go
CREATE TRIGGER trig_sysmail_profile_delete
ON msdb.dbo.sysmail_profile
FOR DELETE
AS
BEGIN
DELETE FROM msdb.dbo.sysmail_profileaccount
WHERE profile_id IN (SELECT profile_id FROM deleted)
END
go
PRINT ''
PRINT 'Creating trigger trig_sysmail_servertype...'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'trig_sysmail_servertype')
AND (type = 'TR')))
DROP TRIGGER dbo.trig_sysmail_servertype
go
CREATE TRIGGER trig_sysmail_servertype
ON msdb.dbo.sysmail_servertype
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
IF (TRIGGER_NESTLEVEL( OBJECT_ID('dbo.trig_sysmail_servertype'), 'AFTER' , 'DML' ) <= 1)
BEGIN
UPDATE msdb.dbo.sysmail_servertype
SET last_mod_datetime = getdate(),last_mod_user = suser_sname()
FROM sysmail_servertype s, inserted i
where s.servertype = i.servertype
END
END
go
SET NOCOUNT ON
IF NOT EXISTS(SELECT * FROM dbo.sysmail_servertype WHERE servertype = N'SMTP')
BEGIN
INSERT INTO dbo.sysmail_servertype (servertype) VALUES (N'SMTP')
END
SET NOCOUNT OFF
go
PRINT ''
PRINT 'Creating trigger trig_sysmail_server...'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'trig_sysmail_server')
AND (type = 'TR')))
DROP TRIGGER dbo.trig_sysmail_server
go
CREATE TRIGGER trig_sysmail_server
ON msdb.dbo.sysmail_server
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
IF (TRIGGER_NESTLEVEL( OBJECT_ID('dbo.trig_sysmail_server'), 'AFTER' , 'DML' ) <= 1)
BEGIN
UPDATE msdb.dbo.sysmail_server
SET last_mod_datetime = getdate(),last_mod_user = suser_sname()
FROM sysmail_server s, inserted i
WHERE s.account_id = i.account_id and s.servertype = i.servertype
END
END
go
PRINT ''
PRINT 'Creating trigger trig_sysmail_configuration...'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'trig_sysmail_configuration')
AND (type = 'TR')))
DROP TRIGGER dbo.trig_sysmail_configuration
go
CREATE TRIGGER trig_sysmail_configuration
ON msdb.dbo.sysmail_configuration
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
IF (TRIGGER_NESTLEVEL( OBJECT_ID('dbo.trig_sysmail_configuration'), 'AFTER' , 'DML' ) <= 1)
BEGIN
UPDATE msdb.dbo.sysmail_configuration
SET last_mod_datetime = getdate(),last_mod_user = suser_sname()
FROM sysmail_configuration c, inserted i
WHERE c.paramname = i.paramname
END
END
go
-------------------------------------------------------------------------
-- Database Mail: triggers on general mail host database specific tables
-------------------------------------------------------------------------
IF (OBJECT_ID('dbo.trig_sysmail_mailitems', 'TR') IS NOT NULL)
DROP TRIGGER dbo.trig_sysmail_mailitems
GO
CREATE TRIGGER trig_sysmail_mailitems
ON msdb.dbo.sysmail_mailitems
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
IF (TRIGGER_NESTLEVEL( OBJECT_ID('dbo.trig_sysmail_mailitems'), 'AFTER' , 'DML' ) <= 1)
BEGIN
UPDATE msdb.dbo.sysmail_mailitems
SET last_mod_date = GETDATE(), last_mod_user = SUSER_SNAME()
FROM sysmail_mailitems m, inserted i
WHERE m.mailitem_id = i.mailitem_id
END
END
GO
IF (OBJECT_ID('dbo.trig_sysmail_attachments', 'TR') IS NOT NULL)
DROP TRIGGER dbo.trig_sysmail_attachments
GO
CREATE TRIGGER trig_sysmail_attachments
ON msdb.dbo.sysmail_attachments
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
IF (TRIGGER_NESTLEVEL( OBJECT_ID('dbo.trig_sysmail_attachments'), 'AFTER' , 'DML' ) <= 1)
BEGIN
UPDATE msdb.dbo.sysmail_attachments
SET last_mod_date = GETDATE(), last_mod_user = SUSER_SNAME()
FROM sysmail_attachments a, inserted i
WHERE a.attachment_id = i.attachment_id
END
END
GO
IF (OBJECT_ID('dbo.trig_sysmail_log', 'TR') IS NOT NULL)
DROP TRIGGER dbo.trig_sysmail_log
GO
CREATE TRIGGER trig_sysmail_log
ON msdb.dbo.sysmail_log
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
IF (TRIGGER_NESTLEVEL( OBJECT_ID('dbo.trig_sysmail_log'), 'AFTER' , 'DML' ) <= 1)
BEGIN
UPDATE msdb.dbo.sysmail_log
SET last_mod_date = GETDATE(), last_mod_user = SUSER_SNAME()
FROM sysmail_log l, inserted i
WHERE l.log_id = i.log_id
END
END
GO
/*********************************************************************************/
/* */
/* Database Mail Utility Functions */
/* */
/*********************************************************************************/
-----------------------------------------------------------
-- ConvertToInt : Converts a string to integer. Returns null
-- if the input string is not a valid int.
--
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.ConvertToInt', 'FN') IS NULL
DROP FUNCTION dbo.ConvertToInt
GO
CREATE FUNCTION dbo.ConvertToInt(@string nvarchar(255), @maxValue int, @defValue int) RETURNS int
AS
BEGIN
DECLARE @value bigint
SET @value = @defValue
SET @string = LTRIM(RTRIM(@string))
-- Check if there is any character other than 0-9 in the string.
IF ((@string IS NOT NULL AND @string <> N'') AND (@string NOT LIKE '%[^0-9]%'))
BEGIN
--INT's have a max of 10 digits
IF(LEN(@string) <= 10)
BEGIN
-- Try converting to bigint. Return default if the value is bigger than @maxValue
SET @value = CONVERT(bigint, @string)
IF(@value > CONVERT(bigint, @maxValue))
SET @value = @defValue
END
END
RETURN CONVERT(int, @value)
END
GO
/*********************************************************************************/
/* */
/* Database Mail Stored Procedures */
/* */
/*********************************************************************************/
-------------------------------------------------------
-- Database Mail: configuration stored procedures
-------------------------------------------------------
PRINT ''
PRINT 'Creating procedure sysmail_verify_accountparams_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_verify_accountparams_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_verify_accountparams_sp
go
CREATE PROCEDURE dbo.sysmail_verify_accountparams_sp
@use_default_credentials bit,
@mailserver_type sysname OUTPUT, -- @mailserver_type must be provided. Usually SMTP
@username nvarchar(128) OUTPUT, -- returns trimmed value, NULL if empty
@password nvarchar(128) OUTPUT -- returns trimmed value, NULL if empty
AS
SET @username = LTRIM(RTRIM(@username))
SET @password = LTRIM(RTRIM(@password))
SET @mailserver_type = LTRIM(RTRIM(@mailserver_type))
IF(@username = N'') SET @username = NULL
IF(@password = N'') SET @password = NULL
IF(@mailserver_type = N'') SET @mailserver_type = NULL
IF(@mailserver_type IS NULL)
BEGIN
RAISERROR(14614, -1, -1, @mailserver_type)
RETURN (1)
END
-- default credentials should supercede any explicit credentials passed in
IF((@use_default_credentials = 1) AND (@username IS NOT NULL))
BEGIN
RAISERROR(14666, -1, -1)
RETURN (1)
END
--If a password is specified then @username must be a non empty string
IF((@password IS NOT NULL) AND (@username IS NULL))
BEGIN
RAISERROR(14615, -1, -1)
RETURN (1)
END
RETURN(0) -- SUCCESS
go
--
-- Stored Proc:
-- sysmail_verify_addressparams_sp
-- It is an internal SP that verifies if the given address is in the correct format.
--
-- Some valid email addresses are:
--
-- user@host
-- "Display Name" <user@host>
-- "Doe, John" <user@host>
--
--
-- DBMail supports only the first format: user@host, which is separated by a delimiter semicolon (;).
-- Since the comma and semicolon are most confusing delimiters to users, this function only checks
-- comma (,) as the invalid delimiter to fix the bug VSTS 160781.
--
-- On the other hand, the function name is reserved to support more formats than the comma delimiter in
-- the future extension.
--
--
-- Parameters:
-- @address -- The string of address that will be verified
-- @parameter_name -- The name of parameter that will be shown in error message to tell users
-- which parameter is wrong.
-- For example, the name is '@recipients' or '@replyto_address'.
--
PRINT ''
PRINT 'Creating procedure sysmail_verify_addressparams_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_verify_addressparams_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_verify_addressparams_sp
go
CREATE PROCEDURE dbo.sysmail_verify_addressparams_sp
@address VARCHAR(MAX),
@parameter_name NVARCHAR(32)
AS
IF ((@address IS NOT NULL) AND (@address != N''))
BEGIN
DECLARE @commaIndex int
SET @commaIndex = CHARINDEX(',', @address)
IF (@commaIndex > 0)
BEGIN
-- Comma is the wrong format to separate addresses. Users should use the semicolon ";".
RAISERROR(14613, 16, 1, @parameter_name, @address)
RETURN(1)
END
END
RETURN(0) -- SUCCESS
go
PRINT ''
PRINT 'Creating procedure sysmail_verify_principal_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_verify_principal_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_verify_principal_sp
go
CREATE PROCEDURE dbo.sysmail_verify_principal_sp
@principal_id int,
@principal_name sysname,
@allow_both_nulls bit,
@principal_sid varbinary(85) OUTPUT
AS
IF @allow_both_nulls = 0
BEGIN
-- at least one parameter must be supplied
IF (@principal_id IS NULL AND @principal_name IS NULL)
BEGIN
RAISERROR(14604, -1, -1, 'principal')
RETURN(1)
END
END
DECLARE @principalid int
IF (@principal_id IS NOT NULL AND @principal_name IS NOT NULL) -- both parameters supplied
BEGIN
SELECT @principalid=principal_id FROM msdb.sys.database_principals
WHERE type in ('U','S','G') AND principal_id = @principal_id AND name = @principal_name
IF (@principalid IS NULL)
BEGIN
RAISERROR(14605, -1, -1, 'principal')
RETURN(2)
END
END
ELSE IF (@principal_id IS NOT NULL) -- use id
BEGIN
SELECT @principalid=principal_id FROM msdb.sys.database_principals
WHERE type in ('U','S','G') AND principal_id = @principal_id
IF (@principalid IS NULL)
BEGIN
RAISERROR(14606, -1, -1, 'principal')
RETURN(3)
END
END
ELSE IF (@principal_name IS NOT NULL) -- use name
BEGIN
SELECT @principalid=principal_id FROM msdb.sys.database_principals
WHERE type in ('U','S','G') AND name = @principal_name
IF (@principalid IS NULL)
BEGIN
RAISERROR(14607, -1, -1, 'principal')
RETURN(4)
END
END
-- populate return variable
SELECT @principal_sid = dbo.get_principal_sid(@principalid)
RETURN(0) -- SUCCESS
go
PRINT ''
PRINT 'Creating procedure sysmail_verify_profile_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_verify_profile_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_verify_profile_sp
go
CREATE PROCEDURE dbo.sysmail_verify_profile_sp
@profile_id int,
@profile_name sysname,
@allow_both_nulls bit,
@allow_id_name_mismatch bit,
@profileid int OUTPUT
AS
IF @allow_both_nulls = 0
BEGIN
-- at least one parameter must be supplied
IF (@profile_id IS NULL AND @profile_name IS NULL)
BEGIN
RAISERROR(14604, -1, -1, 'profile')
RETURN(1)
END
END
IF ((@allow_id_name_mismatch = 0) AND (@profile_id IS NOT NULL AND @profile_name IS NOT NULL)) -- use both parameters
BEGIN
SELECT @profileid = profile_id FROM msdb.dbo.sysmail_profile WHERE profile_id=@profile_id AND name=@profile_name
IF (@profileid IS NULL) -- id and name do not match
BEGIN
RAISERROR(14605, -1, -1, 'profile')
RETURN(2)
END
END
ELSE IF (@profile_id IS NOT NULL) -- use id
BEGIN
SELECT @profileid = profile_id FROM msdb.dbo.sysmail_profile WHERE profile_id=@profile_id
IF (@profileid IS NULL) -- id is invalid
BEGIN
RAISERROR(14606, -1, -1, 'profile')
RETURN(3)
END
END
ELSE IF (@profile_name IS NOT NULL) -- use name
BEGIN
SELECT @profileid = profile_id FROM msdb.dbo.sysmail_profile WHERE name=@profile_name
IF (@profileid IS NULL) -- name is invalid
BEGIN
RAISERROR(14607, -1, -1, 'profile')
RETURN(4)
END
END
RETURN(0) -- SUCCESS
go
PRINT ''
PRINT 'Creating procedure sysmail_verify_account_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_verify_account_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_verify_account_sp
go
CREATE PROCEDURE dbo.sysmail_verify_account_sp
@account_id int,
@account_name sysname,
@allow_both_nulls bit,
@allow_id_name_mismatch bit,
@accountid int OUTPUT
AS
IF @allow_both_nulls = 0
BEGIN
-- at least one parameter must be supplied
IF (@account_id IS NULL AND @account_name IS NULL)
BEGIN
RAISERROR(14604, -1, -1, 'account')
RETURN(1)
END
END
IF ((@allow_id_name_mismatch = 0) AND (@account_id IS NOT NULL AND @account_name IS NOT NULL)) -- use both parameters
BEGIN
SELECT @accountid = account_id FROM msdb.dbo.sysmail_account WHERE account_id=@account_id AND name=@account_name
IF (@accountid IS NULL) -- id and name do not match
BEGIN
RAISERROR(14605, -1, -1, 'account')
RETURN(2)
END
END
ELSE IF (@account_id IS NOT NULL) -- use id
BEGIN
SELECT @accountid = account_id FROM msdb.dbo.sysmail_account WHERE account_id=@account_id
IF (@accountid IS NULL) -- id is invalid
BEGIN
RAISERROR(14606, -1, -1, 'account')
RETURN(3)
END
END
ELSE IF (@account_name IS NOT NULL) -- use name
BEGIN
SELECT @accountid = account_id FROM msdb.dbo.sysmail_account WHERE name=@account_name
IF (@accountid IS NULL) -- name is invalid
BEGIN
RAISERROR(14607, -1, -1, 'account')
RETURN(4)
END
END
RETURN(0) -- SUCCESS
go
PRINT ''
PRINT 'Creating procedure sysmail_add_profile_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_add_profile_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_add_profile_sp
go
CREATE PROCEDURE dbo.sysmail_add_profile_sp
@profile_name sysname,
@description nvarchar(256) = NULL,
@profile_id int = NULL OUTPUT
AS
SET NOCOUNT ON
-- insert new profile record, rely on primary key constraint to error out
INSERT INTO msdb.dbo.sysmail_profile (name,description) VALUES (@profile_name, @description)
-- fetch back profile_id
SELECT @profile_id = profile_id FROM msdb.dbo.sysmail_profile WHERE name = @profile_name
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_update_profile_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_update_profile_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_update_profile_sp
go
CREATE PROCEDURE dbo.sysmail_update_profile_sp
@profile_id int = NULL, -- must provide either id or name
@profile_name sysname = NULL,
@description nvarchar(256) = NULL
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @profileid int
exec @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id, @profile_name, 0, 1, @profileid OUTPUT
IF @rc <> 0
RETURN(1)
IF (@profile_name IS NOT NULL AND @description IS NOT NULL)
UPDATE msdb.dbo.sysmail_profile
SET name=@profile_name, description = @description
WHERE profile_id = @profileid
ELSE IF (@profile_name IS NOT NULL)
UPDATE msdb.dbo.sysmail_profile
SET name=@profile_name
WHERE profile_id = @profileid
ELSE IF (@description IS NOT NULL)
UPDATE msdb.dbo.sysmail_profile
SET description = @description
WHERE profile_id = @profileid
ELSE
BEGIN
RAISERROR(14610, -1, -1)
RETURN(1)
END
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_delete_profile_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_delete_profile_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_delete_profile_sp
go
USE [msdb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE PROCEDURE [dbo].[sysmail_delete_profile_sp]
@profile_id int = NULL, -- must provide either id or name
@profile_name sysname = NULL,
@force_delete BIT = 1
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @profileid int
exec @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id, @profile_name, 0, 0, @profileid OUTPUT
IF @rc <> 0
RETURN(1)
IF(EXISTS (select * from sysmail_unsentitems WHERE
sysmail_unsentitems.profile_id = @profileid) AND @force_delete <> 1)
BEGIN
IF(@profile_name IS NULL)
BEGIN
select @profile_name = name from dbo.sysmail_profile WHERE profile_id = @profileid
END
RAISERROR(14668, -1, -1, @profile_name)
RETURN (1)
END
UPDATE [msdb].[dbo].[sysmail_mailitems]
SET [sent_status] = 2, [sent_date] = getdate()
WHERE profile_id = @profileid AND sent_status <> 1
DELETE FROM msdb.dbo.sysmail_profile
WHERE profile_id = @profileid
RETURN(0)
GO
PRINT ''
PRINT 'Creating procedure sysmail_help_profile_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_help_profile_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_help_profile_sp
go
CREATE PROCEDURE dbo.sysmail_help_profile_sp
@profile_id int = NULL,
@profile_name sysname = NULL
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @profileid int
exec @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id, @profile_name, 1, 0, @profileid OUTPUT
IF @rc <> 0
RETURN(1)
IF (@profileid IS NOT NULL)
SELECT profile_id, name, description
FROM msdb.dbo.sysmail_profile
WHERE profile_id = @profileid
ELSE -- don't filter the output
SELECT profile_id, name, description
FROM msdb.dbo.sysmail_profile
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_create_user_credential_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_create_user_credential_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_create_user_credential_sp
go
CREATE PROCEDURE dbo.sysmail_create_user_credential_sp
@username nvarchar(128),
@password nvarchar(128),
@credential_id int OUTPUT
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @credential_name UNIQUEIDENTIFIER
DECLARE @credential_name_as_str varchar(40)
DECLARE @sql NVARCHAR(max)
-- create a GUID as the name for the credential
SET @credential_name = newid()
SET @credential_name_as_str = convert(varchar(40), @credential_name)
SET @sql = N'CREATE CREDENTIAL [' + @credential_name_as_str
+ N'] WITH IDENTITY = ' + QUOTENAME(@username, '''')
+ N', SECRET = ' + QUOTENAME(ISNULL(@password, N''), '''')
EXEC @rc = sp_executesql @statement = @sql
IF(@rc <> 0)
RETURN @rc
SELECT @credential_id = credential_id
FROM sys.credentials
WHERE name = convert(sysname, @credential_name)
IF(@credential_id IS NULL)
BEGIN
RAISERROR(14616, -1, -1, @credential_name_as_str)
RETURN 1
END
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_alter_user_credential_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_alter_user_credential_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_alter_user_credential_sp
go
CREATE PROCEDURE dbo.sysmail_alter_user_credential_sp
@credential_name sysname,
@username nvarchar(128),
@password nvarchar(128)
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @sql NVARCHAR(max)
-- alter credential DDL
SET @sql = N'ALTER CREDENTIAL ' + QUOTENAME(@credential_name)
+ N' WITH IDENTITY = ' + QUOTENAME(@username, '''')
+ N', SECRET = ' + QUOTENAME(ISNULL(@password, N''), '''')
EXEC @rc = sp_executesql @statement = @sql
IF(@rc <> 0)
RETURN @rc
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_drop_user_credential_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_drop_user_credential_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_drop_user_credential_sp
go
CREATE PROCEDURE dbo.sysmail_drop_user_credential_sp
@credential_name sysname
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @sql NVARCHAR(max)
-- Drop credential DDL
SET @sql = N'DROP CREDENTIAL ' + QUOTENAME(@credential_name)
EXEC @rc = sp_executesql @statement = @sql
IF(@rc <> 0)
RETURN @rc
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_add_account_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_add_account_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_add_account_sp
go
CREATE PROCEDURE dbo.sysmail_add_account_sp
@account_name sysname,
@email_address nvarchar(128),
@display_name nvarchar(128) = NULL,
@replyto_address nvarchar(128) = NULL,
@description nvarchar(256) = NULL,
@mailserver_name sysname = NULL, -- the following fields are part of server definition
@mailserver_type sysname = N'SMTP',
@port int = 25,
@username nvarchar(128) = NULL,
@password nvarchar(128) = NULL,
@use_default_credentials bit = 0,
@enable_ssl bit = 0,
@account_id int = NULL OUTPUT
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @credential_id int
EXEC @rc = msdb.dbo.sysmail_verify_accountparams_sp
@use_default_credentials = @use_default_credentials,
@mailserver_type = @mailserver_type OUTPUT, -- validates and returns trimmed value
@username = @username OUTPUT, -- returns trimmed value, NULL if empty
@password = @password OUTPUT -- returns trimmed value, NULL if empty
IF(@rc <> 0)
RETURN (1)
EXEC @rc = msdb.dbo.sysmail_verify_addressparams_sp @address = @replyto_address, @parameter_name='@replyto_address'
IF (@rc <> 0)
RETURN @rc
--transact this in case sysmail_create_user_credential_sp fails
BEGIN TRANSACTION
-- insert new account record, rely on primary key constraint to error out
INSERT INTO msdb.dbo.sysmail_account (name,description,email_address,display_name,replyto_address)
VALUES (@account_name,@description,@email_address,@display_name,@replyto_address)
IF (@@ERROR <> 0)
BEGIN
ROLLBACK TRANSACTION
RETURN (2)
END
-- fetch back account_id
SELECT @account_id = account_id FROM msdb.dbo.sysmail_account WHERE name = @account_name
IF (@mailserver_name IS NULL) -- use local server as default
SELECT @mailserver_name=@@SERVERNAME
--create a credential in the credential store if a password needs to be stored
IF(@username IS NOT NULL)
BEGIN
EXEC @rc = msdb.dbo.sysmail_create_user_credential_sp
@username,
@password,
@credential_id OUTPUT
IF(@rc <> 0)
BEGIN
ROLLBACK TRANSACTION
RETURN (3)
END
END
INSERT INTO msdb.dbo.sysmail_server (account_id,servertype,servername,port,username,credential_id,use_default_credentials,enable_ssl)
VALUES (@account_id,@mailserver_type,@mailserver_name,@port,@username,@credential_id,@use_default_credentials,@enable_ssl)
IF (@@ERROR <> 0)
BEGIN
ROLLBACK TRANSACTION
RETURN (4)
END
COMMIT TRANSACTION
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_update_account_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_update_account_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_update_account_sp
go
USE [msdb]
GO
/****** Object: StoredProcedure [dbo].[sysmail_update_account_sp] Script Date: 06/26/2006 10:45:40 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE PROCEDURE [dbo].[sysmail_update_account_sp]
@account_id int = NULL, -- must provide either id or name
@account_name sysname = NULL,
@email_address nvarchar(128) = NULL,
@display_name nvarchar(128) = NULL,
@replyto_address nvarchar(128) = NULL,
@description nvarchar(256) = NULL,
@mailserver_name sysname = NULL,
@mailserver_type sysname = NULL,
@port int = NULL,
@username sysname = NULL,
@password sysname = NULL,
@use_default_credentials bit = NULL,
@enable_ssl bit = NULL,
@timeout int = NULL,
@no_credential_change bit = NULL -- BOOL
-- WITH EXECUTE AS OWNER --Allows access to sys.credentials
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @accountid int
DECLARE @credential_id int
DECLARE @credential_name sysname
SELECT @no_credential_change = ISNULL(@no_credential_change, 0)
exec @rc = msdb.dbo.sysmail_verify_account_sp @account_id, @account_name, 0, 1, @accountid OUTPUT
IF @rc <> 0
RETURN(1)
IF(@email_address IS NULL)
BEGIN
SELECT @email_address = email_address FROM msdb.dbo.sysmail_account WHERE account_id=@accountid
END
IF(@display_name IS NULL)
BEGIN
SELECT @display_name = display_name FROM msdb.dbo.sysmail_account WHERE account_id=@accountid
END
IF(@replyto_address IS NULL)
BEGIN
SELECT @replyto_address = replyto_address FROM msdb.dbo.sysmail_account WHERE account_id=@accountid
END
EXEC @rc = msdb.dbo.sysmail_verify_addressparams_sp @address = @replyto_address, @parameter_name='@replyto_address'
IF (@rc <> 0)
RETURN @rc
IF(@description IS NULL)
BEGIN
SELECT @description = description FROM msdb.dbo.sysmail_account WHERE account_id=@accountid
END
IF(@port IS NULL)
BEGIN
SELECT @port = port FROM msdb.dbo.sysmail_server WHERE account_id=@accountid
END
IF(@use_default_credentials IS NULL)
BEGIN
SELECT @use_default_credentials = use_default_credentials FROM msdb.dbo.sysmail_server WHERE account_id=@accountid
END
IF(@enable_ssl IS NULL)
BEGIN
SELECT @enable_ssl = enable_ssl FROM msdb.dbo.sysmail_server WHERE account_id=@accountid
END
IF(@timeout IS NULL)
BEGIN
SELECT @timeout = timeout FROM msdb.dbo.sysmail_server WHERE account_id=@accountid
END
IF(@mailserver_type IS NULL)
BEGIN
SELECT @mailserver_type = servertype FROM msdb.dbo.sysmail_server WHERE account_id=@accountid
END
EXEC @rc = msdb.dbo.sysmail_verify_accountparams_sp
@use_default_credentials = @use_default_credentials,
@mailserver_type = @mailserver_type OUTPUT, -- validates and returns trimmed value
@username = @username OUTPUT, -- returns trimmed value
@password = @password OUTPUT -- returns empty string if @username is given and @password is null
IF(@rc <> 0)
RETURN (1)
--transact this in case credential updates fail
BEGIN TRAN
-- update account table
IF (@account_name IS NOT NULL)
IF (@email_address IS NOT NULL)
UPDATE msdb.dbo.sysmail_account
SET name=@account_name, description=@description, email_address=@email_address, display_name=@display_name, replyto_address=@replyto_address
WHERE account_id=@accountid
ELSE
UPDATE msdb.dbo.sysmail_account
SET name=@account_name, description=@description, display_name=@display_name, replyto_address=@replyto_address
WHERE account_id=@accountid
ELSE
IF (@email_address IS NOT NULL)
UPDATE msdb.dbo.sysmail_account
SET description=@description, email_address=@email_address, display_name=@display_name, replyto_address=@replyto_address
WHERE account_id=@accountid
ELSE
UPDATE msdb.dbo.sysmail_account
SET description=@description, display_name=@display_name, replyto_address=@replyto_address
WHERE account_id=@accountid
-- see if a credential has been stored for this account
SELECT @credential_name = name,
@credential_id = c.credential_id
FROM sys.credentials as c
JOIN msdb.dbo.sysmail_server as ms
ON c.credential_id = ms.credential_id
WHERE account_id = @accountid
AND servertype = @mailserver_type
--update the credential store
IF((@credential_name IS NOT NULL) AND (@no_credential_change = 0))
BEGIN
--Remove the unneed credential
IF(@username IS NULL)
BEGIN
SET @credential_id = NULL
EXEC @rc = msdb.dbo.sysmail_drop_user_credential_sp
@credential_name = @credential_name
END
-- Update the credential
ELSE
BEGIN
EXEC @rc = msdb.dbo.sysmail_alter_user_credential_sp
@credential_name = @credential_name,
@username = @username,
@password = @password
END
IF(@rc <> 0)
BEGIN
ROLLBACK TRAN
RETURN (1)
END
END
-- create a new credential if one doesn't exist
ELSE IF(@credential_name IS NULL AND @username IS NOT NULL)
BEGIN
EXEC @rc = msdb.dbo.sysmail_create_user_credential_sp
@username = @username,
@password = @password,
@credential_id = @credential_id OUTPUT
IF(@rc <> 0)
BEGIN
ROLLBACK TRAN
RETURN (1)
END
END
-- update server table
IF (@no_credential_change = 0)
BEGIN
IF (@mailserver_name IS NOT NULL)
UPDATE msdb.dbo.sysmail_server
SET servername=@mailserver_name, port=@port, username=@username, credential_id = @credential_id, use_default_credentials = @use_default_credentials, enable_ssl = @enable_ssl, timeout = @timeout
WHERE account_id=@accountid AND servertype=@mailserver_type
ELSE
UPDATE msdb.dbo.sysmail_server
SET port=@port, username=@username, credential_id = @credential_id, use_default_credentials = @use_default_credentials, enable_ssl = @enable_ssl, timeout = @timeout
WHERE account_id=@accountid AND servertype=@mailserver_type
END
ELSE
BEGIN
-- Since no_credential_change is true, @username is empty. Do not pass it.
-- If we gave @username, sysmail_server would be set with the empty @username.
IF (@mailserver_name IS NOT NULL)
UPDATE msdb.dbo.sysmail_server
SET servername=@mailserver_name, port=@port, credential_id = @credential_id, use_default_credentials = @use_default_credentials, enable_ssl = @enable_ssl, timeout = @timeout
WHERE account_id=@accountid AND servertype=@mailserver_type
ELSE
UPDATE msdb.dbo.sysmail_server
SET port=@port, credential_id = @credential_id, use_default_credentials = @use_default_credentials, enable_ssl = @enable_ssl, timeout = @timeout
WHERE account_id=@accountid AND servertype=@mailserver_type
END
COMMIT TRAN
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_delete_account_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_delete_account_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_delete_account_sp
go
CREATE PROCEDURE dbo.sysmail_delete_account_sp
@account_id int = NULL, -- must provide either id or name
@account_name sysname = NULL
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @accountid int
DECLARE @credential_name sysname
exec @rc = msdb.dbo.sysmail_verify_account_sp @account_id, @account_name, 0, 0, @accountid OUTPUT
IF @rc <> 0
RETURN(1)
-- Get all the credentials has been stored for this account
DECLARE cur CURSOR FOR
SELECT c.name
FROM sys.credentials as c
JOIN msdb.dbo.sysmail_server as ms
ON c.credential_id = ms.credential_id
WHERE account_id = @accountid
OPEN cur
FETCH NEXT FROM cur INTO @credential_name
WHILE @@FETCH_STATUS = 0
BEGIN
-- drop the credential
EXEC msdb.dbo.sysmail_drop_user_credential_sp @credential_name = @credential_name
FETCH NEXT FROM cur INTO @credential_name
END
CLOSE cur
DEALLOCATE cur
DELETE FROM msdb.dbo.sysmail_account
WHERE account_id = @accountid
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_help_account_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_help_account_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_help_account_sp
go
CREATE PROCEDURE dbo.sysmail_help_account_sp
@account_id int = NULL,
@account_name sysname = NULL
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @accountid int
exec @rc = msdb.dbo.sysmail_verify_account_sp @account_id, @account_name, 1, 0, @accountid OUTPUT
IF @rc <> 0
RETURN(1)
IF (@accountid IS NOT NULL)
SELECT a.account_id, a.name, a.description, a.email_address, a.display_name, a.replyto_address, s.servertype, s.servername, s.port, s.username, s.use_default_credentials, s.enable_ssl
FROM msdb.dbo.sysmail_account a, msdb.dbo.sysmail_server s
WHERE a.account_id = s.account_id AND a.account_id = @accountid
ELSE
SELECT a.account_id, a.name, a.description, a.email_address, a.display_name, a.replyto_address, s.servertype, s.servername, s.port, s.username, s.use_default_credentials, s.enable_ssl
FROM msdb.dbo.sysmail_account a, msdb.dbo.sysmail_server s
WHERE a.account_id = s.account_id
RETURN(0)
go
-- Access to the complete account info. Required by databasemail.exe
PRINT ''
PRINT 'Creating procedure sysmail_help_admin_account_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_help_admin_account_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_help_admin_account_sp
go
CREATE PROCEDURE dbo.sysmail_help_admin_account_sp
@account_id int
AS
SET NOCOUNT ON
DECLARE @rc int,
@acc_id int,
@name sysname,
@description nvarchar(256),
@email_address nvarchar(128),
@display_name nvarchar(128),
@replyto_address nvarchar(128),
@servertype sysname,
@servername sysname,
@port int,
@username nvarchar(128),
@passwordsize int,
@cryptpassword varbinary(1024),
@credential_id int,
@use_default_credentials bit,
@enable_ssl bit,
@timeout int
SET @passwordsize = 0
EXEC @rc = msdb.dbo.sysmail_verify_account_sp @account_id, NULL, 1, 0, NULL
IF @rc <> 0
RETURN(1)
SELECT
@acc_id = a.account_id,
@name = a.name,
@description = a.description,
@email_address = a.email_address,
@display_name = a.display_name,
@replyto_address= a.replyto_address,
@servertype = s.servertype,
@servername = s.servername,
@port = s.port,
@username = s.username,
@credential_id = s.credential_id,
@use_default_credentials = s.use_default_credentials,
@enable_ssl = s.enable_ssl,
@timeout = s.timeout
FROM msdb.dbo.sysmail_account a, msdb.dbo.sysmail_server s
WHERE (a.account_id = s.account_id) AND
(a.account_id = @account_id)
--get the encrypted password if required
IF(@username IS NOT NULL)
BEGIN
DECLARE @cred TABLE([size] INT, blob VARBINARY(1024));
INSERT @cred
EXEC @rc = master.dbo.sp_PostAgentInfo @credential_id
IF @rc <> 0
BEGIN
RETURN(1)
END
SELECT @passwordsize = [size], @cryptpassword = [blob]
FROM @cred
END
--All done return result
SELECT
@acc_id as 'account_id',
@name as 'name',
@description as 'description',
@email_address as 'email_address',
@display_name as 'display_name',
@replyto_address as 'replyto_address',
@servertype as 'servertype',
@servername as 'servername',
@port as 'port',
@username as 'username',
@passwordsize as 'password_size',
@cryptpassword as 'password_crypt',
@use_default_credentials as 'use_default_credentials',
@enable_ssl as 'enable_ssl',
@timeout as 'timeout'
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_add_profileaccount_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_add_profileaccount_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_add_profileaccount_sp
go
CREATE PROCEDURE dbo.sysmail_add_profileaccount_sp
@profile_id int = NULL, -- must provide id or name
@profile_name sysname = NULL,
@account_id int = NULL, -- must provide id or name
@account_name sysname = NULL,
@sequence_number int -- account with the lowest sequence number is picked as default
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @profileid int
DECLARE @accountid int
exec @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id, @profile_name, 0, 0, @profileid OUTPUT
IF @rc <> 0
RETURN(1)
exec @rc = msdb.dbo.sysmail_verify_account_sp @account_id, @account_name, 0, 0, @accountid OUTPUT
IF @rc <> 0
RETURN(2)
-- insert new account record, rely on primary key constraint to error out
INSERT INTO msdb.dbo.sysmail_profileaccount (profile_id,account_id,sequence_number)
VALUES (@profileid,@accountid,@sequence_number)
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_update_profileaccount_sp...'
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmail_update_profileaccount_sp')
AND (type = 'P')))
DROP PROCEDURE dbo.sysmail_update_profileaccount_sp
go
CREATE PROCEDURE dbo.sysmail_update_profileaccount_sp
@profile_id int = NULL, -- must provide id or name
@profile_name sysname = NULL,
@account_id int = NULL, -- must provide id or name
@account_name sysname = NULL,
@sequence_number int -- account with the lowest sequence number is picked as default
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @profileid int
DECLARE @accountid int
exec @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id, @profile_name, 0, 0, @profileid OUTPUT
IF @rc <> 0
RETURN(1)
exec @rc = msdb.dbo.sysmail_verify_account_sp @account_id, @account_name, 0, 0, @accountid OUTPUT
IF @rc <> 0
RETURN(2)
IF (@sequence_number IS NULL)
BEGIN
RAISERROR(14611, -1, -1)
RETURN(3)
END
UPDATE msdb.dbo.sysmail_profileaccount
SET sequence_number=@sequence_number
WHERE profile_id=@profileid AND account_id=@accountid
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_delete_profileaccount_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_delete_profileaccount_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_delete_profileaccount_sp
go
CREATE PROCEDURE dbo.sysmail_delete_profileaccount_sp
@profile_id int = NULL, -- must provide id or name
@profile_name sysname = NULL,
@account_id int = NULL, -- must provide id or name
@account_name sysname = NULL
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @profileid int
DECLARE @accountid int
exec @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id, @profile_name, 1, 0, @profileid OUTPUT
IF @rc <> 0
RETURN(1)
exec @rc = msdb.dbo.sysmail_verify_account_sp @account_id, @account_name, 1, 0, @accountid OUTPUT
IF @rc <> 0
RETURN(2)
IF (@profileid IS NOT NULL AND @accountid IS NOT NULL) -- both parameters supplied for deletion
DELETE FROM msdb.dbo.sysmail_profileaccount
WHERE profile_id=@profileid AND account_id=@accountid
ELSE IF (@profileid IS NOT NULL) -- profile id is supplied
DELETE FROM msdb.dbo.sysmail_profileaccount
WHERE profile_id=@profileid
ELSE IF (@accountid IS NOT NULL) -- account id is supplied
DELETE FROM msdb.dbo.sysmail_profileaccount
WHERE account_id=@accountid
ELSE -- no parameters are supplied for deletion
BEGIN
RAISERROR(14608, -1, -1, 'profile', 'account')
RETURN(3)
END
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_help_profileaccount_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_help_profileaccount_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_help_profileaccount_sp
go
CREATE PROCEDURE dbo.sysmail_help_profileaccount_sp
@profile_id int = NULL, -- must provide id or name
@profile_name sysname = NULL,
@account_id int = NULL, -- must provide id or name
@account_name sysname = NULL
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @profileid int
DECLARE @accountid int
exec @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id, @profile_name, 1, 0, @profileid OUTPUT
IF @rc <> 0
RETURN(1)
exec @rc = msdb.dbo.sysmail_verify_account_sp @account_id, @account_name, 1, 0, @accountid OUTPUT
IF @rc <> 0
RETURN(2)
IF (@profileid IS NOT NULL AND @accountid IS NOT NULL)
SELECT p.profile_id,profile_name=p.name,a.account_id,account_name=a.name,c.sequence_number
FROM msdb.dbo.sysmail_profile p, msdb.dbo.sysmail_account a, msdb.dbo.sysmail_profileaccount c
WHERE p.profile_id=c.profile_id AND a.account_id=c.account_id AND c.profile_id=@profileid AND c.account_id=@accountid
ELSE IF (@profileid IS NOT NULL)
SELECT p.profile_id,profile_name=p.name,a.account_id,account_name=a.name,c.sequence_number
FROM msdb.dbo.sysmail_profile p, msdb.dbo.sysmail_account a, msdb.dbo.sysmail_profileaccount c
WHERE p.profile_id=c.profile_id AND a.account_id=c.account_id AND c.profile_id=@profileid
ELSE IF (@accountid IS NOT NULL)
SELECT p.profile_id,profile_name=p.name,a.account_id,account_name=a.name,c.sequence_number
FROM msdb.dbo.sysmail_profile p, msdb.dbo.sysmail_account a, msdb.dbo.sysmail_profileaccount c
WHERE p.profile_id=c.profile_id AND a.account_id=c.account_id AND c.account_id=@accountid
ELSE
SELECT p.profile_id,profile_name=p.name,a.account_id,account_name=a.name,c.sequence_number
FROM msdb.dbo.sysmail_profile p, msdb.dbo.sysmail_account a, msdb.dbo.sysmail_profileaccount c
WHERE p.profile_id=c.profile_id AND a.account_id=c.account_id
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_configure_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_configure_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_configure_sp
go
CREATE PROCEDURE dbo.sysmail_configure_sp
@parameter_name nvarchar(256),
@parameter_value nvarchar(256),
@description nvarchar(256) = NULL
AS
SET NOCOUNT ON
IF (@description IS NOT NULL)
UPDATE msdb.dbo.sysmail_configuration
SET paramvalue=@parameter_value, description=@description
WHERE paramname=@parameter_name
ELSE
UPDATE msdb.dbo.sysmail_configuration
SET paramvalue=@parameter_value
WHERE paramname=@parameter_name
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_help_configure_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_help_configure_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_help_configure_sp
go
CREATE PROCEDURE dbo.sysmail_help_configure_sp
@parameter_name nvarchar(256) = NULL
AS
SET NOCOUNT ON
SELECT paramname, paramvalue, description
FROM msdb.dbo.sysmail_configuration
WHERE paramname = ISNULL(@parameter_name, paramname)
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_help_configure_value_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_help_configure_value_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_help_configure_value_sp
go
CREATE PROCEDURE dbo.sysmail_help_configure_value_sp
@parameter_name nvarchar(256),
@parameter_value nvarchar(256) OUTPUT
AS
SET NOCOUNT ON
SET @parameter_value = NULL
IF (@parameter_name IS NULL)
BEGIN
RAISERROR(14618, 16, 1, '@parameter_name')
RETURN(1)
END
SELECT @parameter_value = paramvalue
FROM msdb.dbo.sysmail_configuration
WHERE paramname = @parameter_name
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_add_principalprofile_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_add_principalprofile_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_add_principalprofile_sp
go
CREATE PROCEDURE dbo.sysmail_add_principalprofile_sp
@principal_id int = NULL, -- must provide id or name
@principal_name sysname = NULL,
@profile_id int = NULL, -- must provide id or name
@profile_name sysname = NULL,
@is_default bit
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @principal_sid varbinary(85)
DECLARE @profileid int
IF (@principal_id IS NOT NULL AND @principal_id = 0) OR (@principal_name IS NOT NULL AND @principal_name = N'public')
BEGIN
IF (@principal_id IS NOT NULL AND @principal_id <> 0) OR (@principal_name IS NOT NULL AND @principal_name <> N'public')
BEGIN
RAISERROR(14605, -1, -1, 'principal') -- id and name do not match
END
SET @principal_sid = 0x00 -- public
END
ELSE
BEGIN
exec @rc = msdb.dbo.sysmail_verify_principal_sp @principal_id, @principal_name, 0, @principal_sid OUTPUT
IF @rc <> 0
RETURN(2)
END
exec @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id, @profile_name, 0, 0, @profileid OUTPUT
IF @rc <> 0
RETURN(3)
-- insert new account record, rely on primary key constraint to error out
INSERT INTO msdb.dbo.sysmail_principalprofile (principal_sid,profile_id,is_default)
VALUES (@principal_sid,@profileid,@is_default)
IF (@is_default IS NOT NULL AND @is_default = 1 )
BEGIN
-- a principal can only have one default profile so reset other, if there are any
UPDATE msdb.dbo.sysmail_principalprofile
SET is_default=0
WHERE principal_sid = @principal_sid AND profile_id <> @profileid
END
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_update_principalprofile_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_update_principalprofile_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_update_principalprofile_sp
go
CREATE PROCEDURE dbo.sysmail_update_principalprofile_sp
@principal_id int = NULL, -- must provide id or name
@principal_name sysname = NULL,
@profile_id int = NULL, -- must provide id or name
@profile_name sysname = NULL,
@is_default bit
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @principal_sid varbinary(85)
DECLARE @profileid int
IF (@principal_id IS NOT NULL AND @principal_id = 0) OR (@principal_name IS NOT NULL AND @principal_name = N'public')
BEGIN
IF (@principal_id IS NOT NULL AND @principal_id <> 0) OR (@principal_name IS NOT NULL AND @principal_name <> N'public')
BEGIN
RAISERROR(14605, -1, -1, 'principal') -- id and name do not match
END
SET @principal_sid = 0x00 -- public
END
ELSE
BEGIN
exec @rc = msdb.dbo.sysmail_verify_principal_sp @principal_id, @principal_name, 0, @principal_sid OUTPUT
IF @rc <> 0
RETURN(1)
END
exec @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id, @profile_name, 0, 0, @profileid OUTPUT
IF @rc <> 0
RETURN(2)
UPDATE msdb.dbo.sysmail_principalprofile
SET is_default=@is_default
WHERE principal_sid = @principal_sid AND profile_id = @profileid
IF (@is_default IS NOT NULL AND @is_default = 1)
BEGIN
-- a principal can only have one default profile so reset others (if there are any)
UPDATE msdb.dbo.sysmail_principalprofile
SET is_default=0
WHERE principal_sid = @principal_sid AND profile_id <> @profileid
END
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_delete_principalprofile_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_delete_principalprofile_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_delete_principalprofile_sp
go
CREATE PROCEDURE dbo.sysmail_delete_principalprofile_sp
@principal_id int = NULL, -- must provide id or name
@principal_name sysname = NULL,
@profile_id int = NULL, -- must provide id or name
@profile_name sysname = NULL
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @principal_sid varbinary(85)
DECLARE @profileid int
IF (@principal_id IS NOT NULL AND @principal_id = 0) OR (@principal_name IS NOT NULL AND @principal_name = N'public')
BEGIN
IF (@principal_id IS NOT NULL AND @principal_id <> 0) OR (@principal_name IS NOT NULL AND @principal_name <> N'public')
BEGIN
RAISERROR(14605, -1, -1, 'principal') -- id and name do not match
END
SET @principal_sid = 0x00 -- public
END
ELSE
BEGIN
IF (@principal_id IS NOT NULL OR @principal_name IS NOT NULL)
BEGIN
exec @rc = msdb.dbo.sysmail_verify_principal_sp @principal_id, @principal_name, 1, @principal_sid OUTPUT
IF @rc <> 0
RETURN(1)
END
END
exec @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id, @profile_name, 1, 0, @profileid OUTPUT
IF @rc <> 0
RETURN(2)
IF ((@principal_id IS NOT NULL OR @principal_name IS NOT NULL) AND @profileid IS NOT NULL)
BEGIN
DELETE FROM msdb.dbo.sysmail_principalprofile WHERE principal_sid=@principal_sid AND profile_id = @profileid
END
ELSE IF (@principal_id IS NOT NULL OR @principal_name IS NOT NULL)
BEGIN
DELETE FROM msdb.dbo.sysmail_principalprofile WHERE principal_sid=@principal_sid
END
ELSE IF (@profileid IS NOT NULL)
BEGIN
DELETE FROM msdb.dbo.sysmail_principalprofile WHERE profile_id = @profileid
END
ELSE -- no parameters are supplied for deletion
BEGIN
RAISERROR(14608, -1, -1, 'principal', 'profile')
RETURN(6)
END
RETURN(0)
go
PRINT ''
PRINT 'Creating procedure sysmail_help_principalprofile_sp...'
IF (NOT OBJECT_ID(N'dbo.sysmail_help_principalprofile_sp', 'P') IS NULL)
DROP PROCEDURE dbo.sysmail_help_principalprofile_sp
go
CREATE PROCEDURE dbo.sysmail_help_principalprofile_sp
@principal_id int = NULL, -- must provide id or name
@principal_name sysname = NULL,
@profile_id int = NULL, -- must provide id or name
@profile_name sysname = NULL
AS
SET NOCOUNT ON
DECLARE @rc int
DECLARE @principal_sid varbinary(85)
DECLARE @profileid int
exec @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id, @profile_name, 1, 0, @profileid OUTPUT
IF @rc <> 0
RETURN(1)
IF (@principal_id IS NOT NULL AND @principal_id = 0) OR (@principal_name IS NOT NULL AND @principal_name = N'public')
BEGIN
IF (@principal_id IS NOT NULL AND @principal_id <> 0) OR (@principal_name IS NOT NULL AND @principal_name <> N'public')
BEGIN
RAISERROR(14605, -1, -1, 'principal') -- id and name do not match
END
SET @principal_sid = 0x00 -- public
IF (@profileid IS NOT NULL)
BEGIN
SELECT principal_id=0,
principal_name = N'public',
prof.profile_id,
profile_name=prof.name,
prin.is_default
FROM msdb.dbo.sysmail_principalprofile prin, msdb.dbo.sysmail_profile prof
WHERE prin.profile_id=prof.profile_id AND
prin.principal_sid = @principal_sid AND
prof.profile_id=@profileid
END
ELSE
BEGIN
SELECT principal_id=0,
principal_name = N'public',
prof.profile_id,
profile_name=prof.name,
prin.is_default
FROM msdb.dbo.sysmail_principalprofile prin, msdb.dbo.sysmail_profile prof
WHERE prin.profile_id=prof.profile_id AND
prin.principal_sid = @principal_sid
END
END
ELSE -- non-public profiles
BEGIN
IF (@principal_id IS NOT NULL OR @principal_name IS NOT NULL)
BEGIN
exec @rc = msdb.dbo.sysmail_verify_principal_sp @principal_id, @principal_name, 1, @principal_sid OUTPUT
IF @rc <> 0
RETURN(2)
END
IF ((@principal_id IS NOT NULL OR @principal_name IS NOT NULL) AND @profileid IS NOT NULL)
BEGIN
SELECT principal_id=dbprin.principal_id,
principal_name=dbprin.name,
prof.profile_id,
profile_name=prof.name,
prinprof.is_default
FROM sys.database_principals dbprin, msdb.dbo.sysmail_principalprofile prinprof, msdb.dbo.sysmail_profile prof
WHERE dbprin.principal_id = dbo.get_principal_id(prinprof.principal_sid) AND
(prinprof.principal_sid = @principal_sid OR prinprof.principal_sid = 0x00) AND
prof.profile_id = prinprof.profile_id AND
prinprof.profile_id = @profileid
END
ELSE IF (@principal_id IS NOT NULL OR @principal_name IS NOT NULL)
BEGIN
SELECT principal_id=dbprin.principal_id,
principal_name=dbprin.name,
prof.profile_id,
profile_name=prof.name,
prinprof.is_default
FROM sys.database_principals dbprin, msdb.dbo.sysmail_principalprofile prinprof, msdb.dbo.sysmail_profile prof
WHERE dbprin.principal_id = dbo.get_principal_id(prinprof.principal_sid) AND
(prinprof.principal_sid = @principal_sid OR prinprof.principal_sid = 0x00) AND
prof.profile_id = prinprof.profile_id
END
ELSE IF (@profileid IS NOT NULL)
BEGIN
SELECT principal_id=dbprin.principal_id,
principal_name=dbprin.name,
prof.profile_id,
profile_name=prof.name,
prinprof.is_default
FROM sys.database_principals dbprin, msdb.dbo.sysmail_principalprofile prinprof, msdb.dbo.sysmail_profile prof
WHERE dbprin.principal_id = dbo.get_principal_id(prinprof.principal_sid) AND
prof.profile_id = prinprof.profile_id AND
prinprof.profile_id = @profileid
END
ELSE -- no parameters are supplied for filtering
BEGIN
SELECT principal_id=dbprin.principal_id,
principal_name=dbprin.name,
prof.profile_id,
profile_name=prof.name,
prinprof.is_default
FROM sys.database_principals dbprin, msdb.dbo.sysmail_principalprofile prinprof, msdb.dbo.sysmail_profile prof
WHERE dbprin.principal_id = dbo.get_principal_id(prinprof.principal_sid) AND
prof.profile_id = prinprof.profile_id
END
END
RETURN(0)
go
-----------------------------------------------------------
-- Database Mail: mail host database stored procedures
-----------------------------------------------------------
-----------------------------------------------------------
-- procedure sysmail_logmailevent_sp
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sysmail_logmailevent_sp', 'P') IS NULL
DROP PROCEDURE dbo.sysmail_logmailevent_sp
GO
-----
PRINT 'Creating sysmail_logmailevent_sp'
-----
GO
-- sysmail_logmailevent_sp : inserts an entry in the sysmail_log table
CREATE PROCEDURE sysmail_logmailevent_sp
@event_type INT,
@description NVARCHAR(max) = NULL,
@process_id INT = NULL,
@mailitem_id INT = NULL,
@account_id INT = NULL
AS
SET NOCOUNT ON
--Try and get the optional logging level for the DatabaseMail process
DECLARE @loggingLevel nvarchar(256)
EXEC msdb.dbo.sysmail_help_configure_value_sp @parameter_name = N'LoggingLevel',
@parameter_value = @loggingLevel OUTPUT
DECLARE @loggingLevelInt int
SET @loggingLevelInt = dbo.ConvertToInt(@loggingLevel, 3, 2)
IF (@event_type = 3) OR -- error
(@event_type = 2 AND @loggingLevelInt >= 2) OR -- warning with extended logging
(@event_type = 1 AND @loggingLevelInt >= 2) OR -- info with extended logging
(@event_type = 0 AND @loggingLevelInt >= 3) -- success with verbose logging
BEGIN
INSERT sysmail_log(event_type, description, process_id, mailitem_id, account_id)
VALUES(@event_type, @description, @process_id , @mailitem_id, @account_id)
END
RETURN 0
GO
-----------------------------------------------------------
-- procedure sysmail_start_sp
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sysmail_start_sp', 'P') IS NULL
DROP PROCEDURE dbo.sysmail_start_sp
GO
-----
PRINT 'Creating sysmail_start_sp'
-----
GO
-- sysmail_start_sp : allows databasemail to process mail from the queue
CREATE PROCEDURE sysmail_start_sp
AS
SET NOCOUNT ON
DECLARE @rc INT
DECLARE @localmessage nvarchar(255)
ALTER QUEUE ExternalMailQueue WITH STATUS = ON
SELECT @rc = @@ERROR
IF(@rc = 0)
BEGIN
ALTER QUEUE ExternalMailQueue WITH ACTIVATION (STATUS = ON);
SET @localmessage = FORMATMESSAGE(14639, SUSER_SNAME())
exec msdb.dbo.sysmail_logmailevent_sp @event_type=1, @description=@localmessage
END
RETURN @rc
GO
-----------------------------------------------------------
-- procedure sysmail_stop_sp
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sysmail_stop_sp', 'P') IS NULL
DROP PROCEDURE dbo.sysmail_stop_sp
GO
-----
PRINT 'Creating sysmail_stop_sp'
-----
GO
-- sysmail_stop_sp : stops the DatabaseMail process. Mail items remain in the queue until sqlmail started
CREATE PROCEDURE sysmail_stop_sp
AS
SET NOCOUNT ON
DECLARE @rc INT
DECLARE @localmessage nvarchar(255)
ALTER QUEUE ExternalMailQueue WITH ACTIVATION (STATUS = OFF);
SELECT @rc = @@ERROR
IF(@rc = 0)
BEGIN
ALTER QUEUE ExternalMailQueue WITH STATUS = OFF;
SELECT @rc = @@ERROR
IF(@rc = 0)
BEGIN
SET @localmessage = FORMATMESSAGE(14640, SUSER_SNAME())
exec msdb.dbo.sysmail_logmailevent_sp @event_type=1, @description=@localmessage
END
END
RETURN @rc
GO
-----------------------------------------------------------
-- procedure sysmail_help_status_sp
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sysmail_help_status_sp', 'P') IS NULL
DROP PROCEDURE dbo.sysmail_help_status_sp
GO
-----
PRINT 'Creating sysmail_help_status_sp'
-----
GO
CREATE PROCEDURE sysmail_help_status_sp
WITH EXECUTE AS 'dbo'
AS
BEGIN
IF NOT EXISTS (SELECT * FROM sys.service_queues WHERE name = N'ExternalMailQueue' AND is_receive_enabled = 1)
SELECT 'STOPPED' AS Status
ELSE
SELECT 'STARTED' AS Status
END
GO
-----------------------------------------------------------
-- procedure sysmail_help_queue_sp
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sysmail_help_queue_sp', 'P') IS NULL
DROP PROCEDURE dbo.sysmail_help_queue_sp
GO
-----
PRINT 'Creating sysmail_help_queue_sp'
-----
GO
CREATE PROCEDURE sysmail_help_queue_sp
@queue_type nvarchar(6) = NULL -- Type of queue
AS
BEGIN
SELECT @queue_type = LTRIM(RTRIM(@queue_type))
IF @queue_type = '' SELECT @queue_type = NULL
IF ( (@queue_type IS NOT NULL) AND
(LOWER(@queue_type collate SQL_Latin1_General_CP1_CS_AS) NOT IN ( N'mail', N'status') ) )
BEGIN
RAISERROR(14266, -1, -1, '@queue_type', 'mail, status')
RETURN(1) -- Failure
END
DECLARE @depth int
DECLARE @temp TABLE (
queue_type nvarchar(6),
length INT NOT NULL,
state nvarchar(64),
last_empty_rowset_time DATETIME,
last_activated_time DATETIME
)
IF ( (@queue_type IS NULL) OR (LOWER(@queue_type collate SQL_Latin1_General_CP1_CS_AS) = N'mail' ) )
BEGIN
SET @depth = (SELECT COUNT(*) FROM ExternalMailQueue WITH (NOWAIT NOLOCK READUNCOMMITTED))
INSERT INTO @temp
SELECT
N'mail',
@depth,
qm.state as state,
qm.last_empty_rowset_time as last_empty_rowset_time,
qm.last_activated_time as last_activated_time
FROM sys.dm_broker_queue_monitors qm
JOIN sys.service_queues sq ON sq.object_id = qm.queue_id
WHERE sq.name = 'ExternalMailQueue'
END
IF ( (@queue_type IS NULL) OR (LOWER(@queue_type collate SQL_Latin1_General_CP1_CS_AS) = N'status' ) )
BEGIN
SET @depth = (SELECT COUNT(*) FROM InternalMailQueue WITH (NOWAIT NOLOCK READUNCOMMITTED))
INSERT INTO @temp
SELECT
N'status',
@depth,
qm.state as state,
qm.last_empty_rowset_time as last_empty_rowset_time,
qm.last_activated_time as last_activated_time
FROM sys.dm_broker_queue_monitors qm
JOIN sys.service_queues sq ON sq.object_id = qm.queue_id
WHERE sq.name = 'InternalMailQueue'
END
SELECT * from @temp
END
GO
-----------------------------------------------------------
-- procedure sp_SendMailMessage
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_SendMailMessage', 'P') IS NULL
DROP PROCEDURE dbo.sp_SendMailMessage
GO
-----
PRINT 'Creating sp_SendMailMessage'
-----
GO
-- sp_SendMailMessage : Sends a request on the mail items SSB queue
CREATE PROCEDURE sp_SendMailMessage
@contract_name sysname, -- Name of contract
@message_type sysname, -- Type of message
@request varchar(max) -- XML message to send
WITH EXECUTE AS 'dbo'
AS
SET NOCOUNT ON
DECLARE @conversationHandle uniqueidentifier;
DECLARE @error int
-- Start a conversation with the remote service
BEGIN DIALOG @conversationHandle
FROM SERVICE [InternalMailService]
TO SERVICE 'ExternalMailService'
ON CONTRACT @contract_name
WITH ENCRYPTION=OFF
-- Check error
SET @error = @@ERROR
IF @error <> 0
BEGIN
RETURN @error
END
-- Send message
;SEND ON CONVERSATION @conversationHandle MESSAGE TYPE @message_type (@request)
-- Check error
SET @error = @@ERROR
IF @error <> 0
BEGIN
RETURN @error
END
RETURN 0
GO
-----------------------------------------------------------
-- procedure sp_isprohibited
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_isprohibited', 'P') IS NULL
DROP PROCEDURE dbo.sp_isprohibited
GO
-----
PRINT 'Creating sp_isprohibited'
-----
GO
-- sp_isprohibited : To test if the attachment is prohibited or not.
--
CREATE PROCEDURE sp_isprohibited
@attachment nvarchar(max),
@prohibitedextensions nvarchar(1000)
AS
DECLARE @extensionIndex int
DECLARE @extensionName nvarchar(255)
IF (@attachment IS NOT NULL AND LEN(@attachment) > 0)
BEGIN
SET @prohibitedextensions = UPPER(@prohibitedextensions)
-- find @extensionName: the substring between the last '.' and the end of the string
SET @extensionIndex = 0
WHILE (1=1)
BEGIN
DECLARE @lastExtensionIndex int
SET @lastExtensionIndex = CHARINDEX('.', @attachment, @extensionIndex+1)
IF (@lastExtensionIndex = 0)
BREAK
SET @extensionIndex = @lastExtensionIndex
END
IF (@extensionIndex > 0)
BEGIN
SET @extensionName = SUBSTRING(@attachment, @extensionIndex + 1, (LEN(@attachment) - @extensionIndex))
SET @extensionName = UPPER(@extensionName)
-- compare @extensionName with each extension in the comma-separated @prohibitedextensions list
DECLARE @currentExtensionStart int
DECLARE @currentExtensionEnd int
SET @currentExtensionStart = 0
SET @currentExtensionEnd = 0
WHILE (@currentExtensionEnd < LEN(@prohibitedextensions))
BEGIN
SET @currentExtensionEnd = CHARINDEX(',', @prohibitedextensions, @currentExtensionStart)
IF (@currentExtensionEnd = 0) -- we have reached the last extension of the list, or the list was empty
SET @currentExtensionEnd = LEN(@prohibitedextensions)+1
DECLARE @prohibitedExtension nvarchar(1000)
SET @prohibitedExtension = SUBSTRING(@prohibitedextensions, @currentExtensionStart, @currentExtensionEnd - @currentExtensionStart)
SET @prohibitedExtension = RTRIM(LTRIM(@prohibitedExtension))
IF( @extensionName = @prohibitedExtension )
RETURN 1
SET @currentExtensionStart = @currentExtensionEnd + 1
END
END
RETURN 0
END
GO
-----------------------------------------------------------
-- procedure sp_SendMailQueues
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_SendMailQueues', 'P') IS NULL
DROP PROCEDURE dbo.sp_SendMailQueues
GO
-----
PRINT 'Creating sp_SendMailQueues'
-----
GO
-- sp_SendMailQueues : Writes a send mail request to the queue.
--
CREATE PROCEDURE sp_SendMailQueues
@message_data varchar(max) -- The request in XML
AS
BEGIN
SET NOCOUNT ON
DECLARE @contract_name nvarchar(128)
DECLARE @message_type nvarchar(128)
DECLARE @retValue int
SET @message_type = '{//www.microsoft.com/databasemail/messages}SendMail'
SET @contract_name = '//www.microsoft.com/databasemail/contracts/SendMail/v1.0'
--Writes the message to the queue
EXEC @retValue = sp_SendMailMessage @contract_name, @message_type, @message_data
RETURN @retValue
END
GO
-----------------------------------------------------------
-- procedure sp_ProcessResponse
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_ProcessResponse', 'P') IS NULL
DROP PROCEDURE dbo.sp_ProcessResponse
GO
-----
PRINT 'Creating sp_ProcessResponse'
-----
USE [msdb]
GO
SET ANSI_NULLS ON
GO
-- Turn on QUOTED IDENTIFIER to compile this stored proc that uses XQuery
SET QUOTED_IDENTIFIER ON
GO
-- Processes responses from dbmail
--
CREATE PROCEDURE [dbo].[sp_ProcessResponse]
@conv_handle uniqueidentifier,
@message_type_name NVARCHAR(256),
@xml_message_body NVARCHAR(max)
AS
BEGIN
DECLARE
@mailitem_id INT,
@sent_status INT,
@rc INT,
@index INT,
@processId INT,
@sent_date DATETIME,
@localmessage NVARCHAR(max),
@LogMessage NVARCHAR(max),
@retry_hconv uniqueidentifier,
@paramStr NVARCHAR(256),
@accRetryDelay INT
--------------------------
--Always send the response
;SEND ON CONVERSATION @conv_handle MESSAGE TYPE @message_type_name (@xml_message_body)
--
-- Need to handle the case where a sent retry is requested.
-- This is done by setting a conversation timer, The timer with go off in the external queue
-- $ISSUE: 325439 - DBMail: Use XML type for all xml document handling in DBMail stored procs
DECLARE @xmlblob xml
SET @xmlblob = CONVERT(xml, @xml_message_body)
SELECT @mailitem_id = MailResponses.Properties.value('(MailItemId/@Id)[1]', 'int'),
@sent_status = MailResponses.Properties.value('(SentStatus/@Status)[1]', 'int')
FROM @xmlblob.nodes('
declare namespace responses="http://schemas.microsoft.com/databasemail/responses";
/responses:SendMail')
AS MailResponses(Properties)
IF(@mailitem_id IS NULL OR @sent_status IS NULL)
BEGIN
--Log error and continue.
SET @localmessage = FORMATMESSAGE(14652, CONVERT(NVARCHAR(50), @conv_handle), @message_type_name, @xml_message_body)
exec msdb.dbo.sysmail_logmailevent_sp @event_type=3, @description=@localmessage
GOTO ErrorHandler;
END
-- Update the status of the email item
UPDATE msdb.dbo.sysmail_mailitems
SET sent_status = @sent_status
WHERE mailitem_id = @mailitem_id
--
-- A send retry has been requested. Set a conversation timer
IF(@sent_status = 3)
BEGIN
-- Get the associated mail item data for the given @conversation_handle (if it exists)
SELECT @retry_hconv = conversation_handle
FROM sysmail_send_retries as sr
RIGHT JOIN sysmail_mailitems as mi
ON sr.mailitem_id = mi.mailitem_id
WHERE mi.mailitem_id = @mailitem_id
--Must be the first retry attempt. Create a sysmail_send_retries record to track retries
IF(@retry_hconv IS NULL)
BEGIN
INSERT sysmail_send_retries(conversation_handle, mailitem_id) --last_send_attempt_date
VALUES(@conv_handle, @mailitem_id)
END
ELSE
BEGIN
--Update existing retry record
UPDATE sysmail_send_retries
SET last_send_attempt_date = GETDATE(),
send_attempts = send_attempts + 1
WHERE mailitem_id = @mailitem_id
END
--Get the global retry delay time
EXEC msdb.dbo.sysmail_help_configure_value_sp @parameter_name = N'AccountRetryDelay',
@parameter_value = @paramStr OUTPUT
--ConvertToInt will return the default if @paramStr is null
SET @accRetryDelay = dbo.ConvertToInt(@paramStr, 0x7fffffff, 300) -- 5 min default
--Now set the dialog timer. This triggers the send retry
;BEGIN CONVERSATION TIMER (@conv_handle) TIMEOUT = @accRetryDelay
END
ELSE
BEGIN
--Only end theconversation if a retry isn't being attempted
END CONVERSATION @conv_handle
END
-- All done OK
goto ExitProc;
-----------------
-- Error Handler
-----------------
ErrorHandler:
------------------
-- Exit Procedure
------------------
ExitProc:
RETURN (@rc);
END
GO
GO
-- Turn off QUOTED IDENTIFIER after compiling stored proc that uses XQuery
SET QUOTED_IDENTIFIER OFF
GO
-----------------------------------------------------------
-- procedure sp_MailItemResultSets
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_MailItemResultSets', 'P') IS NULL
DROP PROCEDURE dbo.sp_MailItemResultSets
GO
-----
PRINT 'Creating sp_MailItemResultSets'
-----
GO
-- sp_MailItemResultSets :
-- Sends back multiple rowsets with the mail items data
CREATE PROCEDURE sp_MailItemResultSets
@mailitem_id INT,
@profile_id INT,
@conversation_handle uniqueidentifier,
@service_contract_name NVARCHAR(256),
@message_type_name NVARCHAR(256)
AS
BEGIN
SET NOCOUNT ON
--
-- Send back multiple rowsets with the mail items data
----
-- 1) MessageTypeName
SELECT @message_type_name as 'message_type_name',
@service_contract_name as 'service_contract_name',
@conversation_handle as 'conversation_handle',
@mailitem_id as 'mailitem_id'
-----
-- 2) The mail item record from sysmail_mailitems.
SELECT
mi.mailitem_id,
mi.profile_id,
(SELECT name FROM msdb.dbo.sysmail_profile p WHERE p.profile_id = mi.profile_id) as 'profile_name',
mi.recipients,
mi.copy_recipients,
mi.blind_copy_recipients,
mi.subject,
mi.body,
mi.body_format,
mi.importance,
mi.sensitivity,
ISNULL(sr.send_attempts, 0) as retry_attempt,
ISNULL(mi.from_address, '') as from_address,
ISNULL(mi.reply_to, '') as reply_to
FROM sysmail_mailitems as mi
LEFT JOIN sysmail_send_retries as sr
ON sr.mailitem_id = mi.mailitem_id
WHERE mi.mailitem_id = @mailitem_id
-----
-- 3) Account information
SELECT a.account_id,
a.name
FROM msdb.dbo.sysmail_profileaccount as pa
JOIN msdb.dbo.sysmail_account as a
ON pa.account_id = a.account_id
WHERE pa.profile_id = @profile_id
ORDER BY pa.sequence_number
-----
-- 4) Attachments if any
SELECT attachment_id,
mailitem_id,
filename,
filesize,
attachment
FROM sysmail_attachments
WHERE mailitem_id = @mailitem_id
RETURN 0
END
GO
-----------------------------------------------------------
-- procedure sp_process_DialogTimer
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_process_DialogTimer', 'P') IS NULL
DROP PROCEDURE dbo.sp_process_DialogTimer
GO
-----
PRINT 'Creating sp_process_DialogTimer'
-----
GO
-- Processes a DialogTimer message from the the queue. This is used for send mail retries.
-- Returns the mail to be send if a retry is required or logs a failure if max retry count has been reached
CREATE PROCEDURE sp_process_DialogTimer
@conversation_handle uniqueidentifier,
@service_contract_name NVARCHAR(256),
@message_type_name NVARCHAR(256)
AS
BEGIN
SET NOCOUNT ON
-- Declare all variables
DECLARE
@mailitem_id INT,
@profile_id INT,
@send_attempts INT,
@mail_request_date DATETIME,
@localmessage NVARCHAR(255),
@paramStr NVARCHAR(256),
@accRetryAttempts INT
-- Get the associated mail item data for the given @conversation_handle
SELECT @mailitem_id = mi.mailitem_id,
@profile_id = mi.profile_id,
@mail_request_date = mi.send_request_date,
@send_attempts = sr.send_attempts
FROM sysmail_send_retries as sr
JOIN sysmail_mailitems as mi
ON sr.mailitem_id = mi.mailitem_id
WHERE sr.conversation_handle = @conversation_handle
-- If not able to find a mailitem_id return and move to the next message.
-- This could happen if the mail items table was cleared before the retry was fired
IF(@mailitem_id IS NULL)
BEGIN
--Log warning and continue
-- "mailitem_id on conversation %s was not found in the sysmail_send_retries table. This mail item will not be sent."
SET @localmessage = FORMATMESSAGE(14662, convert(NVARCHAR(50), @conversation_handle))
exec msdb.dbo.sysmail_logmailevent_sp @event_type=2, @description=@localmessage
-- Resource clean-up
IF(@conversation_handle IS NOT NULL)
BEGIN
END CONVERSATION @conversation_handle;
END
-- return code has special meaning and will be propagated to the calling process
RETURN 2;
END
--Get the retry attempt count from sysmailconfig.
EXEC msdb.dbo.sysmail_help_configure_value_sp @parameter_name = N'AccountRetryAttempts',
@parameter_value = @paramStr OUTPUT
--ConvertToInt will return the default if @paramStr is null
SET @accRetryAttempts = dbo.ConvertToInt(@paramStr, 0x7fffffff, 1)
--Check the send attempts and log and error if send_attempts >= retry count.
--This shouldn't happen unless the retry configuration was changed
IF(@send_attempts > @accRetryAttempts)
BEGIN
--Log warning and continue
-- "Mail Id %d has exceeded the retry count. This mail item will not be sent."
SET @localmessage = FORMATMESSAGE(14663, @mailitem_id)
exec msdb.dbo.sysmail_logmailevent_sp @event_type=2, @description=@localmessage, @mailitem_id=@mailitem_id
-- Resource clean-up
IF(@conversation_handle IS NOT NULL)
BEGIN
END CONVERSATION @conversation_handle;
END
-- return code has special meaning and will be propagated to the calling process
RETURN 3;
END
-- This returns the mail item to the client as multiple result sets
EXEC sp_MailItemResultSets
@mailitem_id = @mailitem_id,
@profile_id = @profile_id,
@conversation_handle = @conversation_handle,
@service_contract_name = @service_contract_name,
@message_type_name = @message_type_name
RETURN 0
END
GO
-----------------------------------------------------------
-- procedure sp_readrequest
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_readrequest', 'P') IS NULL
DROP PROCEDURE dbo.sp_readrequest
GO
-----
PRINT 'Creating sp_readrequest'
-----
GO
-- Turn on QUOTED IDENTIFIER to compile this stored proc that uses XQuery
SET QUOTED_IDENTIFIER ON
GO
-- sp_readrequest : Reads a request from the the queue and returns its
-- contents.
CREATE PROCEDURE sp_readrequest
@receive_timeout INT -- the max time this read will wait for new message
AS
BEGIN
SET NOCOUNT ON
-- Table to store message information.
DECLARE @msgs TABLE
(
[conversation_handle] uniqueidentifier,
[service_contract_name] nvarchar(256),
[message_type_name] nvarchar(256),
[message_body] varbinary(max)
)
-- Declare variables to store row values fetched from the cursor
DECLARE
@exit INT,
@mailitem_id INT,
@profile_id INT,
@conversation_handle uniqueidentifier,
@service_contract_name NVARCHAR(256),
@message_type_name NVARCHAR(256),
@xml_message_body VARCHAR(max),
@timediff INT,
@rec_timeout INT,
@start_time DATETIME,
@localmessage NVARCHAR(256),
@rc INT
--Init variables
SELECT @start_time = GETDATE(),
@timediff = 0,
@exit = 0,
@rc = 0
WHILE (@timediff <= @receive_timeout)
BEGIN
-- Delete all messages from @msgs table
DELETE FROM @msgs
-- Pick all message from queue
SET @rec_timeout = @receive_timeout - @timediff
WAITFOR(RECEIVE conversation_handle, service_contract_name, message_type_name, message_body
FROM ExternalMailQueue INTO @msgs), TIMEOUT @rec_timeout
-- Check if there was some error in reading from queue
SET @rc = @@ERROR
IF (@rc <> 0)
BEGIN
IF(@rc < 4) -- make sure return code is not in reserved range (1-3)
SET @rc = 4
--Note: we will get error no. 9617 if the service queue 'ExternalMailQueue' is currently disabled.
BREAK
END
--If there is no message in the queue return 1 to indicate a timeout
IF NOT EXISTS(SELECT * FROM @msgs)
BEGIN
SET @rc = 1
BREAK
END
-- Create a cursor to iterate through the messages.
DECLARE msgs_cursor CURSOR FOR
SELECT conversation_handle,
service_contract_name,
message_type_name,
CONVERT(VARCHAR(MAX), message_body)
FROM @msgs;
-- Open the cursor
OPEN msgs_cursor;
-- Perform the first fetch and store the values in the variables.
FETCH NEXT FROM msgs_cursor
INTO
@conversation_handle,
@service_contract_name,
@message_type_name,
@xml_message_body
-- Check @@FETCH_STATUS to see if there are any more rows to fetch.
WHILE (@@FETCH_STATUS = 0)
BEGIN
-- Check if the message is a send mail message
IF(@message_type_name = N'{//www.microsoft.com/databasemail/messages}SendMail')
BEGIN
DECLARE @xmlblob xml
SET @xmlblob = CONVERT(xml, @xml_message_body)
SELECT @mailitem_id = MailRequest.Properties.value('(MailItemId)[1]', 'int')
FROM @xmlblob.nodes('
declare namespace requests="http://schemas.microsoft.com/databasemail/requests";
/requests:SendMail')
AS MailRequest(Properties)
-- get account information
SELECT @profile_id = profile_id
FROM sysmail_mailitems
WHERE mailitem_id = @mailitem_id
IF(@profile_id IS NULL) -- mail item has been deleted from the database
BEGIN
-- log warning
SET @localmessage = FORMATMESSAGE(14667, @mailitem_id)
exec msdb.dbo.sysmail_logmailevent_sp @event_type=2, @description=@localmessage
-- Resource clean-up
IF(@conversation_handle IS NOT NULL)
END CONVERSATION @conversation_handle;
-- return code has special meaning and will be propagated to the calling process
SET @rc = 2
END
ELSE
BEGIN
-- This returns the mail item to the client as multiple result sets
EXEC sp_MailItemResultSets
@mailitem_id = @mailitem_id,
@profile_id = @profile_id,
@conversation_handle = @conversation_handle,
@service_contract_name = @service_contract_name,
@message_type_name = @message_type_name
SET @exit = 1 -- make sure we exit outer loop
END
-- always break from the loop upon processing SendMail message
BREAK
END
-- Check if the message is a dialog timer. This is used for account retries
ELSE IF(@message_type_name = N'http://schemas.microsoft.com/SQL/ServiceBroker/DialogTimer')
BEGIN
-- Handle the retry case. - DialogTimer is used for send mail reties
EXEC @rc = sp_process_DialogTimer
@conversation_handle = @conversation_handle,
@service_contract_name = @service_contract_name,
@message_type_name = N'{//www.microsoft.com/databasemail/messages}SendMail'
-- Always break from the loop upon processing DialogTimer message
-- In case of failure return code from procedure call will simply be propagated to the calling process
SET @exit = 1 -- make sure we exit outer loop
BREAK
END
-- Error case
ELSE IF (@message_type_name = 'http://schemas.microsoft.com/SQL/ServiceBroker/Error')
-- Error in the conversation, hence ignore all the messages of this conversation.
BREAK
-- This is executed as long as fetch succeeds.
FETCH NEXT FROM msgs_cursor
INTO
@conversation_handle,
@service_contract_name,
@message_type_name,
@xml_message_body
END
CLOSE msgs_cursor;
DEALLOCATE msgs_cursor;
-- Check if we read any request or only SSB generated messages
-- If a valid request is read with or without an error break out of loop
IF (@exit = 1 OR @rc <> 0)
BREAK
--Keep track of how long this sp has been running
select @timediff = DATEDIFF(ms, @start_time, getdate())
END
-- propagate return code to the calling process
RETURN @rc
END
GO
-- Turn off QUOTED IDENTIFIER after compiling stored proc that uses XQuery
SET QUOTED_IDENTIFIER OFF
GO
-----------------------------------------------------------
-- procedure sp_GetAttachmentData
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_GetAttachmentData', 'P') IS NULL
DROP PROCEDURE dbo.sp_GetAttachmentData
GO
-----
PRINT 'Creating sp_GetAttachmentData'
-----
GO
CREATE PROCEDURE sp_GetAttachmentData
@attachments nvarchar(max),
@temp_table_uid uniqueidentifier,
@exclude_query_output BIT = 0
AS
BEGIN
SET NOCOUNT ON
SET QUOTED_IDENTIFIER ON
DECLARE @rc INT,
@prohibitedExts NVARCHAR(1000),
@attachFilePath NVARCHAR(260),
@scIndex INT,
@startLocation INT,
@fileSizeStr NVARCHAR(256),
@fileSize INT,
@mailDbName sysname,
@uidStr VARCHAR(36)
--Get the maximum file size allowed for attachments from sysmailconfig.
EXEC msdb.dbo.sysmail_help_configure_value_sp @parameter_name = N'MaxFileSize',
@parameter_value = @fileSizeStr OUTPUT
--ConvertToInt will return the default if @fileSizeStr is null
SET @fileSize = dbo.ConvertToInt(@fileSizeStr, 0x7fffffff, 100000)
--May need this if attaching files
EXEC msdb.dbo.sysmail_help_configure_value_sp @parameter_name = N'ProhibitedExtensions',
@parameter_value = @prohibitedExts OUTPUT
SET @mailDbName = DB_NAME()
SET @uidStr = CONVERT(VARCHAR(36), @temp_table_uid)
SET @attachments = @attachments + ';'
SET @startLocation = 0
SET @scIndex = CHARINDEX(';', @attachments, @startLocation)
WHILE (@scIndex <> 0)
BEGIN
SET @attachFilePath = SUBSTRING(@attachments, @startLocation, (@scIndex - @startLocation))
-- Make sure we have an attachment file name to work with, and that it hasn't been truncated
IF (@scIndex - @startLocation > 260 )
BEGIN
RAISERROR(14628, 16, 1)
RETURN 1
END
IF ((@attachFilePath IS NULL) OR (LEN(@attachFilePath) = 0))
BEGIN
RAISERROR(14628, 16, 1)
RETURN 1
END
--Check if attachment ext is allowed
EXEC @rc = sp_isprohibited @attachFilePath, @prohibitedExts
IF (@rc <> 0)
BEGIN
RAISERROR(14630, 16, 1, @attachFilePath, @prohibitedExts)
RETURN 2
END
DECLARE @no_output_int INT
SET @no_output_int = CONVERT(int, @exclude_query_output)
-- return code checked after select and delete calls
EXEC @rc = master..xp_sysmail_attachment_load @message = @mailDbName,
@attachments = @attachFilePath,
@subject = @uidStr,
@max_attachment_size = @fileSize,
@no_output = @no_output_int
IF (@rc <> 0)
RETURN (@rc)
--Get next substring index
SET @startLocation = @scIndex + 1
SET @scIndex = CHARINDEX(';', @attachments, @startLocation)
IF (@scIndex = 0)
BREAK
END
RETURN 0
END
GO
-----------------------------------------------------------
-- procedure sp_RunMailQuery
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_RunMailQuery', 'P') IS NULL
DROP PROCEDURE dbo.sp_RunMailQuery
GO
-----
PRINT 'Creating sp_RunMailQuery'
-----
USE msdb
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE PROCEDURE [dbo].[sp_RunMailQuery]
@query NVARCHAR(max),
@attach_results BIT,
@query_attachment_filename NVARCHAR(260) = NULL,
@no_output BIT,
@query_result_header BIT,
@separator VARCHAR(1),
@echo_error BIT,
@dbuse sysname,
@width INT,
@temp_table_uid uniqueidentifier,
@query_no_truncate BIT,
@query_result_no_padding BIT
AS
BEGIN
SET NOCOUNT ON
SET QUOTED_IDENTIFIER ON
DECLARE @rc INT,
@prohibitedExts NVARCHAR(1000),
@fileSizeStr NVARCHAR(256),
@fileSize INT,
@attach_res_int INT,
@no_output_int INT,
@no_header_int INT,
@echo_error_int INT,
@query_no_truncate_int INT,
@query_result_no_padding_int INT,
@mailDbName sysname,
@uid uniqueidentifier,
@uidStr VARCHAR(36)
--
--Get config settings and verify parameters
--
SET @query_attachment_filename = LTRIM(RTRIM(@query_attachment_filename))
--Get the maximum file size allowed for attachments from sysmailconfig.
EXEC msdb.dbo.sysmail_help_configure_value_sp @parameter_name = N'MaxFileSize',
@parameter_value = @fileSizeStr OUTPUT
--ConvertToInt will return the default if @fileSizeStr is null
SET @fileSize = dbo.ConvertToInt(@fileSizeStr, 0x7fffffff, 100000)
IF (@attach_results = 1)
BEGIN
--Need this if attaching the query
EXEC msdb.dbo.sysmail_help_configure_value_sp @parameter_name = N'ProhibitedExtensions',
@parameter_value = @prohibitedExts OUTPUT
-- If attaching query results to a file and a filename isn't given create one
IF ((@query_attachment_filename IS NOT NULL) AND (LEN(@query_attachment_filename) > 0))
BEGIN
EXEC @rc = sp_isprohibited @query_attachment_filename, @prohibitedExts
IF (@rc <> 0)
BEGIN
RAISERROR(14630, 16, 1, @query_attachment_filename, @prohibitedExts)
RETURN 2
END
END
ELSE
BEGIN
--If queryfilename is not specified, generate a random name (doesn't have to be unique)
SET @query_attachment_filename = 'QueryResults' + CONVERT(varchar, ROUND(RAND() * 1000000, 0)) + '.txt'
END
END
--Init variables used in the query execution
SET @mailDbName = db_name()
SET @uidStr = convert(varchar(36), @temp_table_uid)
SET @attach_res_int = CONVERT(int, @attach_results)
SET @no_output_int = CONVERT(int, @no_output)
IF(@query_result_header = 0) SET @no_header_int = 1 ELSE SET @no_header_int = 0
SET @echo_error_int = CONVERT(int, @echo_error)
SET @query_no_truncate_int = CONVERT(int, @query_no_truncate)
SET @query_result_no_padding_int = CONVERT(int, @query_result_no_padding )
EXEC @rc = master..xp_sysmail_format_query
@query = @query,
@message = @mailDbName,
@subject = @uidStr,
@dbuse = @dbuse,
@attachments = @query_attachment_filename,
@attach_results = @attach_res_int,
-- format params
@separator = @separator,
@no_header = @no_header_int,
@no_output = @no_output_int,
@echo_error = @echo_error_int,
@max_attachment_size = @fileSize,
@width = @width,
@query_no_truncate = @query_no_truncate_int,
@query_result_no_padding = @query_result_no_padding_int
RETURN @rc
END
GO
-----------------------------------------------------------
-- procedure sp_validate_user, used by sp_send_dbmail
-----------------------------------------------------------
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_validate_user')))
DROP PROCEDURE sp_validate_user
go
use msdb
GO
/****** Object: StoredProcedure [dbo].sp_validate_user ********/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE PROCEDURE [dbo].[sp_validate_user]
@send_request_user sysname,
@user_sid varbinary(85) OUTPUT
WITH EXECUTE AS 'dbo'
AS
BEGIN
SET NOCOUNT ON
-- And make sure ARITHABORT is on. This is the default for yukon DB's
SET ARITHABORT ON
declare @groupSid varbinary(85)
declare @temp table
([account name] sysname,
[type] char(8),
[privilege] char(9),
[mapped login name] sysname,
[permission path] sysname null)
declare @sidlist table
([account name] sysname,
[accountsid] varbinary(85) null,
[permission path] sysname null)
SET @user_sid = NULL
SET @groupSid = NULL
-- Lookup the Windows Group membership, if any, that grants this
-- user access to SQL Server. xp_logininfo may fail if the sql
-- server service account cannot talk to the domain controller to
-- validate the windows username, or it may fail if the
-- @send_request_user is not a valid windows user or group name.
BEGIN TRY
insert @temp exec master.dbo.xp_logininfo @send_request_user, 'all'
-- For a given account name, Get account name -> group accountsid mapping to a temp table variable
insert @sidlist
select [account name], suser_sid([permission path]),[permission path]
from @temp
END TRY
BEGIN CATCH
RETURN 2
END CATCH
-- for a given account name, there has to be atleast one account sid that is not null and
-- there has to be atleast one mail profile for the list of account sids
IF ((EXISTS(SELECT [account name]
FROM @sidlist
WHERE accountsid is not NULL)
AND (EXISTS(SELECT profile_id
FROM msdb.dbo.sysmail_principalprofile pp, @sidlist s
WHERE s.accountsid = pp.principal_sid))))
BEGIN
-- Get the first account's sid that meets following criteria
-- 1) return first default profile (if available)
-- 2) if no default profile is defined, then return the first non-default profile for this account
SELECT TOP 1 @groupSid = accountsid
FROM @sidlist s, msdb.dbo.sysmail_principalprofile pp
WHERE s.accountsid is not NULL
AND s.accountsid = pp.principal_sid
ORDER BY is_default DESC
END
-- Lookup a default profile for the Group. If there is one,
-- then use the group's mail profile.
IF (@groupSid IS NOT NULL)
BEGIN
SET @user_sid = @groupSid
RETURN 0
END
RETURN 1
END
GO
-----------------------------------------------------------
-- procedure sp_send_dbmail
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_send_dbmail', 'P') IS NULL
DROP PROCEDURE dbo.sp_send_dbmail
GO
-----
PRINT 'Creating sp_send_dbmail'
-----
USE msdb
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
-- sp_send_dbmail : Sends a mail from Yukon outbox.
--
CREATE PROCEDURE [dbo].[sp_send_dbmail]
@profile_name sysname = NULL,
@recipients VARCHAR(MAX) = NULL,
@copy_recipients VARCHAR(MAX) = NULL,
@blind_copy_recipients VARCHAR(MAX) = NULL,
@subject NVARCHAR(255) = NULL,
@body NVARCHAR(MAX) = NULL,
@body_format VARCHAR(20) = NULL,
@importance VARCHAR(6) = 'NORMAL',
@sensitivity VARCHAR(12) = 'NORMAL',
@file_attachments NVARCHAR(MAX) = NULL,
@query NVARCHAR(MAX) = NULL,
@execute_query_database sysname = NULL,
@attach_query_result_as_file BIT = 0,
@query_attachment_filename NVARCHAR(260) = NULL,
@query_result_header BIT = 1,
@query_result_width INT = 256,
@query_result_separator CHAR(1) = ' ',
@exclude_query_output BIT = 0,
@append_query_error BIT = 0,
@query_no_truncate BIT = 0,
@query_result_no_padding BIT = 0,
@mailitem_id INT = NULL OUTPUT,
@from_address VARCHAR(max) = NULL,
@reply_to VARCHAR(max) = NULL
WITH EXECUTE AS 'dbo'
AS
BEGIN
SET NOCOUNT ON
-- And make sure ARITHABORT is on. This is the default for yukon DB's
SET ARITHABORT ON
--Declare variables used by the procedure internally
DECLARE @profile_id INT,
@temp_table_uid uniqueidentifier,
@sendmailxml VARCHAR(max),
@CR_str NVARCHAR(2),
@localmessage NVARCHAR(255),
@QueryResultsExist INT,
@AttachmentsExist INT,
@RetErrorMsg NVARCHAR(4000), --Impose a limit on the error message length to avoid memory abuse
@rc INT,
@procName sysname,
@trancountSave INT,
@tranStartedBool INT,
@is_sysadmin BIT,
@send_request_user sysname,
@database_user_id INT,
@sid varbinary(85)
-- Initialize
SELECT @rc = 0,
@QueryResultsExist = 0,
@AttachmentsExist = 0,
@temp_table_uid = NEWID(),
@procName = OBJECT_NAME(@@PROCID),
@tranStartedBool = 0,
@trancountSave = @@TRANCOUNT,
@sid = NULL
EXECUTE AS CALLER
SELECT @is_sysadmin = IS_SRVROLEMEMBER('sysadmin'),
@send_request_user = SUSER_SNAME(),
@database_user_id = USER_ID()
REVERT
--Check if SSB is enabled in this database
IF (ISNULL(DATABASEPROPERTYEX(DB_NAME(), N'IsBrokerEnabled'), 0) <> 1)
BEGIN
RAISERROR(14650, 16, 1)
RETURN 1
END
--Report error if the mail queue has been stopped.
--sysmail_stop_sp/sysmail_start_sp changes the receive status of the SSB queue
IF NOT EXISTS (SELECT * FROM sys.service_queues WHERE name = N'ExternalMailQueue' AND is_receive_enabled = 1)
BEGIN
RAISERROR(14641, 16, 1)
RETURN 1
END
-- Get the relevant profile_id
--
IF (@profile_name IS NULL)
BEGIN
-- Use the global or users default if profile name is not supplied
SELECT TOP (1) @profile_id = pp.profile_id
FROM msdb.dbo.sysmail_principalprofile as pp
WHERE (pp.is_default = 1) AND
(dbo.get_principal_id(pp.principal_sid) = @database_user_id OR pp.principal_sid = 0x00)
ORDER BY dbo.get_principal_id(pp.principal_sid) DESC
--Was a profile found
IF(@profile_id IS NULL)
BEGIN
-- Try a profile lookup based on Windows Group membership, if any
EXEC @rc = msdb.dbo.sp_validate_user @send_request_user, @sid OUTPUT
IF (@rc = 0)
BEGIN
SELECT TOP (1) @profile_id = pp.profile_id
FROM msdb.dbo.sysmail_principalprofile as pp
WHERE (pp.is_default = 1) AND
(pp.principal_sid = @sid)
ORDER BY dbo.get_principal_id(pp.principal_sid) DESC
END
IF(@profile_id IS NULL)
BEGIN
RAISERROR(14636, 16, 1)
RETURN 1
END
END
END
ELSE
BEGIN
--Get primary account if profile name is supplied
EXEC @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id = NULL,
@profile_name = @profile_name,
@allow_both_nulls = 0,
@allow_id_name_mismatch = 0,
@profileid = @profile_id OUTPUT
IF (@rc <> 0)
RETURN @rc
--Make sure this user has access to the specified profile.
--sysadmins can send on any profiles
IF ( @is_sysadmin <> 1)
BEGIN
--Not a sysadmin so check users access to profile
iF NOT EXISTS(SELECT *
FROM msdb.dbo.sysmail_principalprofile
WHERE ((profile_id = @profile_id) AND
(dbo.get_principal_id(principal_sid) = @database_user_id OR principal_sid = 0x00)))
BEGIN
EXEC msdb.dbo.sp_validate_user @send_request_user, @sid OUTPUT
IF(@sid IS NULL)
BEGIN
RAISERROR(14607, -1, -1, 'profile')
RETURN 1
END
END
END
END
--Attach results must be specified
IF @attach_query_result_as_file IS NULL
BEGIN
RAISERROR(14618, 16, 1, 'attach_query_result_as_file')
RETURN 2
END
--No output must be specified
IF @exclude_query_output IS NULL
BEGIN
RAISERROR(14618, 16, 1, 'exclude_query_output')
RETURN 3
END
--No header must be specified
IF @query_result_header IS NULL
BEGIN
RAISERROR(14618, 16, 1, 'query_result_header')
RETURN 4
END
-- Check if query_result_separator is specifed
IF @query_result_separator IS NULL OR DATALENGTH(@query_result_separator) = 0
BEGIN
RAISERROR(14618, 16, 1, 'query_result_separator')
RETURN 5
END
--Echo error must be specified
IF @append_query_error IS NULL
BEGIN
RAISERROR(14618, 16, 1, 'append_query_error')
RETURN 6
END
--@body_format can be TEXT (default) or HTML
IF (@body_format IS NULL)
BEGIN
SET @body_format = 'TEXT'
END
ELSE
BEGIN
SET @body_format = UPPER(@body_format)
IF @body_format NOT IN ('TEXT', 'HTML')
BEGIN
RAISERROR(14626, 16, 1, @body_format)
RETURN 13
END
END
--Importance must be specified
IF @importance IS NULL
BEGIN
RAISERROR(14618, 16, 1, 'importance')
RETURN 15
END
SET @importance = UPPER(@importance)
--Importance must be one of the predefined values
IF @importance NOT IN ('LOW', 'NORMAL', 'HIGH')
BEGIN
RAISERROR(14622, 16, 1, @importance)
RETURN 16
END
--Sensitivity must be specified
IF @sensitivity IS NULL
BEGIN
RAISERROR(14618, 16, 1, 'sensitivity')
RETURN 17
END
SET @sensitivity = UPPER(@sensitivity)
--Sensitivity must be one of predefined values
IF @sensitivity NOT IN ('NORMAL', 'PERSONAL', 'PRIVATE', 'CONFIDENTIAL')
BEGIN
RAISERROR(14623, 16, 1, @sensitivity)
RETURN 18
END
--Message body cannot be null. Atleast one of message, subject, query,
--attachments must be specified.
IF( (@body IS NULL AND @query IS NULL AND @file_attachments IS NULL AND @subject IS NULL)
OR
( (LEN(@body) IS NULL OR LEN(@body) <= 0)
AND (LEN(@query) IS NULL OR LEN(@query) <= 0)
AND (LEN(@file_attachments) IS NULL OR LEN(@file_attachments) <= 0)
AND (LEN(@subject) IS NULL OR LEN(@subject) <= 0)
)
)
BEGIN
RAISERROR(14624, 16, 1, '@body, @query, @file_attachments, @subject')
RETURN 19
END
ELSE
IF @subject IS NULL OR LEN(@subject) <= 0
SET @subject='SQL Server Message'
--Recipients cannot be empty. Atleast one of the To, Cc, Bcc must be specified
IF ( (@recipients IS NULL AND @copy_recipients IS NULL AND
@blind_copy_recipients IS NULL
)
OR
( (LEN(@recipients) IS NULL OR LEN(@recipients) <= 0)
AND (LEN(@copy_recipients) IS NULL OR LEN(@copy_recipients) <= 0)
AND (LEN(@blind_copy_recipients) IS NULL OR LEN(@blind_copy_recipients) <= 0)
)
)
BEGIN
RAISERROR(14624, 16, 1, '@recipients, @copy_recipients, @blind_copy_recipients')
RETURN 20
END
EXEC @rc = msdb.dbo.sysmail_verify_addressparams_sp @address = @recipients, @parameter_name='@recipients'
IF (@rc <> 0)
RETURN @rc
EXEC @rc = msdb.dbo.sysmail_verify_addressparams_sp @address = @copy_recipients, @parameter_name='@copy_recipients'
IF (@rc <> 0)
RETURN @rc
EXEC @rc = msdb.dbo.sysmail_verify_addressparams_sp @address = @blind_copy_recipients, @parameter_name='@blind_copy_recipients'
IF (@rc <> 0)
RETURN @rc
EXEC @rc = msdb.dbo.sysmail_verify_addressparams_sp @address = @reply_to, @parameter_name='@reply_to'
IF (@rc <> 0)
RETURN @rc
--If query is not specified, attach results and no header cannot be true.
IF ( (@query IS NULL OR LEN(@query) <= 0) AND @attach_query_result_as_file = 1)
BEGIN
RAISERROR(14625, 16, 1)
RETURN 21
END
--
-- Execute Query if query is specified
IF ((@query IS NOT NULL) AND (LEN(@query) > 0))
BEGIN
EXECUTE AS CALLER
EXEC @rc = sp_RunMailQuery
@query = @query,
@attach_results = @attach_query_result_as_file,
@query_attachment_filename = @query_attachment_filename,
@no_output = @exclude_query_output,
@query_result_header = @query_result_header,
@separator = @query_result_separator,
@echo_error = @append_query_error,
@dbuse = @execute_query_database,
@width = @query_result_width,
@temp_table_uid = @temp_table_uid,
@query_no_truncate = @query_no_truncate,
@query_result_no_padding = @query_result_no_padding
-- This error indicates that query results size was over the configured MaxFileSize.
-- Note, an error has already beed raised in this case
IF(@rc = 101)
GOTO ErrorHandler;
REVERT
-- Always check the transfer tables for data. They may also contain error messages
-- Only one of the tables receives data in the call to sp_RunMailQuery
IF(@attach_query_result_as_file = 1)
BEGIN
IF EXISTS(SELECT * FROM sysmail_attachments_transfer WHERE uid = @temp_table_uid)
SET @AttachmentsExist = 1
END
ELSE
BEGIN
IF EXISTS(SELECT * FROM sysmail_query_transfer WHERE uid = @temp_table_uid AND uid IS NOT NULL)
SET @QueryResultsExist = 1
END
-- Exit if there was an error and caller doesn't want the error appended to the mail
IF (@rc <> 0 AND @append_query_error = 0)
BEGIN
--Error msg with be in either the attachment table or the query table
--depending on the setting of @attach_query_result_as_file
IF(@attach_query_result_as_file = 1)
BEGIN
--Copy query results from the attachments table to mail body
SELECT @RetErrorMsg = CONVERT(NVARCHAR(4000), attachment)
FROM sysmail_attachments_transfer
WHERE uid = @temp_table_uid
END
ELSE
BEGIN
--Copy query results from the query table to mail body
SELECT @RetErrorMsg = text_data
FROM sysmail_query_transfer
WHERE uid = @temp_table_uid
END
GOTO ErrorHandler;
END
SET @AttachmentsExist = @attach_query_result_as_file
END
ELSE
BEGIN
--If query is not specified, attach results cannot be true.
IF (@attach_query_result_as_file = 1)
BEGIN
RAISERROR(14625, 16, 1)
RETURN 21
END
END
--Get the prohibited extensions for attachments from sysmailconfig.
IF ((@file_attachments IS NOT NULL) AND (LEN(@file_attachments) > 0))
BEGIN
EXECUTE AS CALLER
EXEC @rc = sp_GetAttachmentData
@attachments = @file_attachments,
@temp_table_uid = @temp_table_uid,
@exclude_query_output = @exclude_query_output
REVERT
IF (@rc <> 0)
GOTO ErrorHandler;
IF EXISTS(SELECT * FROM sysmail_attachments_transfer WHERE uid = @temp_table_uid)
SET @AttachmentsExist = 1
END
-- Start a transaction if not already in one.
-- Note: For rest of proc use GOTO ErrorHandler for falures
if (@trancountSave = 0)
BEGIN TRAN @procName
SET @tranStartedBool = 1
-- Store complete mail message for history/status purposes
INSERT sysmail_mailitems
(
profile_id,
recipients,
copy_recipients,
blind_copy_recipients,
subject,
body,
body_format,
importance,
sensitivity,
file_attachments,
attachment_encoding,
query,
execute_query_database,
attach_query_result_as_file,
query_result_header,
query_result_width,
query_result_separator,
exclude_query_output,
append_query_error,
send_request_user,
from_address,
reply_to
)
VALUES
(
@profile_id,
@recipients,
@copy_recipients,
@blind_copy_recipients,
@subject,
@body,
@body_format,
@importance,
@sensitivity,
@file_attachments,
'MIME',
@query,
@execute_query_database,
@attach_query_result_as_file,
@query_result_header,
@query_result_width,
@query_result_separator,
@exclude_query_output,
@append_query_error,
@send_request_user,
@from_address,
@reply_to
)
SELECT @rc = @@ERROR,
@mailitem_id = SCOPE_IDENTITY()
IF(@rc <> 0)
GOTO ErrorHandler;
--Copy query into the message body
IF(@QueryResultsExist = 1)
BEGIN
-- if the body is null initialize it
UPDATE sysmail_mailitems
SET body = N''
WHERE mailitem_id = @mailitem_id
AND body is null
--Add CR, a \r followed by \n, which is 0xd and then 0xa
SET @CR_str = CHAR(13) + CHAR(10)
UPDATE sysmail_mailitems
SET body.WRITE(@CR_str, NULL, NULL)
WHERE mailitem_id = @mailitem_id
--Copy query results to mail body
UPDATE sysmail_mailitems
SET body.WRITE( (SELECT text_data from sysmail_query_transfer WHERE uid = @temp_table_uid), NULL, NULL )
WHERE mailitem_id = @mailitem_id
END
--Copy into the attachments table
IF(@AttachmentsExist = 1)
BEGIN
--Copy temp attachments to sysmail_attachments
INSERT INTO sysmail_attachments(mailitem_id, filename, filesize, attachment)
SELECT @mailitem_id, filename, filesize, attachment
FROM sysmail_attachments_transfer
WHERE uid = @temp_table_uid
END
-- Create the primary SSB xml maessage
SET @sendmailxml = '<requests:SendMail xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.microsoft.com/databasemail/requests RequestTypes.xsd" xmlns:requests="http://schemas.microsoft.com/databasemail/requests"><MailItemId>'
+ CONVERT(NVARCHAR(20), @mailitem_id) + N'</MailItemId></requests:SendMail>'
-- Send the send request on queue.
EXEC @rc = sp_SendMailQueues @sendmailxml
IF @rc <> 0
BEGIN
RAISERROR(14627, 16, 1, @rc, 'send mail')
GOTO ErrorHandler;
END
-- Print success message if required
IF (@exclude_query_output = 0)
BEGIN
SET @localmessage = FORMATMESSAGE(14635, @mailitem_id)
PRINT @localmessage
END
--
-- See if the transaction needs to be commited
--
IF (@trancountSave = 0 and @tranStartedBool = 1)
COMMIT TRAN @procName
-- All done OK
goto ExitProc;
-----------------
-- Error Handler
-----------------
ErrorHandler:
IF (@tranStartedBool = 1)
ROLLBACK TRAN @procName
------------------
-- Exit Procedure
------------------
ExitProc:
--Always delete query and attactment transfer records.
--Note: Query results can also be returned in the sysmail_attachments_transfer table
DELETE sysmail_attachments_transfer WHERE uid = @temp_table_uid
DELETE sysmail_query_transfer WHERE uid = @temp_table_uid
--Raise an error it the query execution fails
-- This will only be the case when @append_query_error is set to 0 (false)
IF( (@RetErrorMsg IS NOT NULL) AND (@exclude_query_output=0) )
BEGIN
RAISERROR(14661, -1, -1, @RetErrorMsg)
END
RETURN (@rc)
END
GO
-----------------------------------------------------------
-- procedure sp_ExternalMailQueueListener
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_ExternalMailQueueListener', 'P') IS NULL
DROP PROCEDURE dbo.sp_ExternalMailQueueListener
GO
-----
PRINT 'Creating sp_ExternalMailQueueListener'
-----
USE [msdb]
GO
SET ANSI_NULLS ON
GO
-- Turn on QUOTED IDENTIFIER to compile this stored proc that uses XQuery
SET QUOTED_IDENTIFIER ON
GO
-- Processes messages from the external mail queue
--
CREATE PROCEDURE [dbo].[sp_ExternalMailQueueListener]
AS
BEGIN
DECLARE
@mailitem_id INT,
@sent_status INT,
@sent_account_id INT,
@rc INT,
@processId INT,
@sent_date DATETIME,
@localmessage NVARCHAR(max),
@conv_handle uniqueidentifier,
@message_type_name NVARCHAR(256),
@xml_message_body NVARCHAR(max),
@LogMessage NVARCHAR(max)
-- Table to store message information.
DECLARE @msgs TABLE
(
[conversation_handle] uniqueidentifier,
[message_type_name] nvarchar(256),
[message_body] varbinary(max)
)
--RECEIVE messages from the external queue.
--MailItem status messages are sent from the external sql mail process along with other SSB notifications and errors
;RECEIVE conversation_handle, message_type_name, message_body FROM InternalMailQueue INTO @msgs
-- Check if there was some error in reading from queue
SET @rc = @@ERROR
IF (@rc <> 0)
BEGIN
--Log error and continue. Don't want to block the following messages on the queue
SET @localmessage = FORMATMESSAGE(@@ERROR)
exec msdb.dbo.sysmail_logmailevent_sp @event_type=3, @description=@localmessage
GOTO ErrorHandler;
END
-----------------------------------
--Process sendmail status messages
SELECT
@conv_handle = conversation_handle,
@message_type_name = message_type_name,
@xml_message_body = CAST(message_body AS NVARCHAR(MAX))
FROM @msgs
WHERE [message_type_name] = N'{//www.microsoft.com/databasemail/messages}SendMailStatus'
IF(@message_type_name IS NOT NULL)
BEGIN
--
--Expecting the xml body to be n the following form:
--
--<?xml version="1.0" encoding="utf-16"?>
--<responses:SendMail xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.microsoft.com/databasemail/responses ResponseTypes.xsd" xmlns:responses="http://schemas.microsoft.com/databasemail/responses">
--<Information>
-- <Failure Message="THe error message...."/>
--</Information>
--<MailItemId Id="1" />
--<SentStatus Status="3" />
--<SentAccountId Id="0" />
--<SentDate Date="2005-03-30T14:55:13" />
--<CallingProcess Id="3012" />
--</responses:SendMail>
DECLARE @xmlblob xml
SET @xmlblob = CONVERT(xml, @xml_message_body)
SELECT @mailitem_id = MailResponses.Properties.value('(MailItemId/@Id)[1]', 'int'),
@sent_status = MailResponses.Properties.value('(SentStatus/@Status)[1]', 'int'),
@sent_account_id = MailResponses.Properties.value('(SentAccountId/@Id)[1]', 'int'),
@sent_date = MailResponses.Properties.value('(SentDate/@Date)[1]', 'DateTime'),
@processId = MailResponses.Properties.value('(CallingProcess/@Id)[1]', 'int'),
@LogMessage = MailResponses.Properties.value('(Information/Failure/@Message)[1]', 'NVARCHAR(max)')
FROM @xmlblob.nodes('
declare namespace responses="http://schemas.microsoft.com/databasemail/responses";
/responses:SendMail')
AS MailResponses(Properties)
IF(@mailitem_id IS NULL)
BEGIN
--Log error and continue. Don't want to block the following messages on the queue by rolling back the tran
SET @localmessage = FORMATMESSAGE(14652, CONVERT(NVARCHAR(50), @conv_handle), @message_type_name, @xml_message_body)
exec msdb.dbo.sysmail_logmailevent_sp @event_type=3, @description=@localmessage
END
ELSE
BEGIN
-- check sent_status is valid : 0(PendingSend), 1(SendSuccessful), 2(SendFailed), 3(AttemptingSendRetry)
IF(@sent_status NOT IN (1, 2, 3))
BEGIN
SET @localmessage = FORMATMESSAGE(14653, N'SentStatus', CONVERT(NVARCHAR(50), @conv_handle), @message_type_name, @xml_message_body)
exec msdb.dbo.sysmail_logmailevent_sp @event_type=2, @description=@localmessage
--Set value to SendFailed
SET @sent_status = 2
END
--Make the @sent_account_id NULL if it is 0.
IF(@sent_account_id IS NOT NULL AND @sent_account_id = 0)
SET @sent_account_id = NULL
--
-- Update the mail status if not a retry. Nothing else needs to be done in this case
UPDATE sysmail_mailitems
SET sent_status = CAST (@sent_status as TINYINT),
sent_account_id = @sent_account_id,
sent_date = @sent_date
WHERE mailitem_id = @mailitem_id
-- Report a failure if no record is found in the sysmail_mailitems table
IF (@@ROWCOUNT = 0)
BEGIN
SET @localmessage = FORMATMESSAGE(14653, N'MailItemId', CONVERT(NVARCHAR(50), @conv_handle), @message_type_name, @xml_message_body)
exec msdb.dbo.sysmail_logmailevent_sp @event_type=3, @description=@localmessage
END
IF (@LogMessage IS NOT NULL)
BEGIN
exec msdb.dbo.sysmail_logmailevent_sp @event_type=3, @description=@LogMessage, @process_id=@processId, @mailitem_id=@mailitem_id, @account_id=@sent_account_id
END
END
END
-------------------------------------------------------
--Process all other messages by logging to sysmail_log
SET @conv_handle = NULL;
--Always end the conversion if this message is received
SELECT @conv_handle = conversation_handle
FROM @msgs
WHERE [message_type_name] = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
IF(@conv_handle IS NOT NULL)
BEGIN
END CONVERSATION @conv_handle;
END
DECLARE @queuemessage nvarchar(max)
DECLARE queue_messages_cursor CURSOR LOCAL
FOR
SELECT FORMATMESSAGE(14654, CONVERT(NVARCHAR(50), conversation_handle), message_type_name, message_body)
FROM @msgs
WHERE [message_type_name]
NOT IN (N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog',
N'{//www.microsoft.com/databasemail/messages}SendMailStatus')
OPEN queue_messages_cursor
FETCH NEXT FROM queue_messages_cursor INTO @queuemessage
WHILE (@@fetch_status = 0)
BEGIN
exec msdb.dbo.sysmail_logmailevent_sp @event_type=2, @description=@queuemessage
FETCH NEXT FROM queue_messages_cursor INTO @queuemessage
END
CLOSE queue_messages_cursor
DEALLOCATE queue_messages_cursor
-- All done OK
goto ExitProc;
-----------------
-- Error Handler
-----------------
ErrorHandler:
------------------
-- Exit Procedure
------------------
ExitProc:
RETURN (@rc)
END
GO
-- Turn off QUOTED IDENTIFIER after compiling stored proc that uses XQuery
SET QUOTED_IDENTIFIER OFF
GO
----------------------------------------------------------
-- procedure sp_sysmail_activate
-----------------------------------------------------------
IF NOT OBJECT_ID('dbo.sp_sysmail_activate', 'P') IS NULL
DROP PROCEDURE dbo.sp_sysmail_activate
GO
-----
PRINT 'Creating sp_sysmail_activate'
-----
USE [msdb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- sp_sysmail_activate : Starts the DatabaseMail process if it isn't already running
--
CREATE PROCEDURE [dbo].[sp_sysmail_activate]
AS
BEGIN
DECLARE @mailDbName sysname
DECLARE @mailDbId INT
DECLARE @mailEngineLifeMin INT
DECLARE @loggingLevel nvarchar(256)
DECLARE @loggingLevelInt int
DECLARE @parameter_value nvarchar(256)
DECLARE @localmessage nvarchar(max)
DECLARE @readFromConfigFile INT
DECLARE @rc INT
SET NOCOUNT ON
EXEC sp_executesql @statement = N'RECEIVE TOP(0) * FROM msdb.dbo.ExternalMailQueue'
EXEC @rc = msdb.dbo.sysmail_help_configure_value_sp @parameter_name = N'DatabaseMailExeMinimumLifeTime',
@parameter_value = @parameter_value OUTPUT
IF(@rc <> 0)
RETURN (1)
--ConvertToInt will return the default if @parameter_value is null or config value can't be converted
--Setting max exe lifetime is 1 week (604800 secs). Can't see a reason for it to ever run longer that this
SET @mailEngineLifeMin = dbo.ConvertToInt(@parameter_value, 604800, 600)
EXEC msdb.dbo.sysmail_help_configure_value_sp @parameter_name = N'ReadFromConfigurationFile',
@parameter_value = @parameter_value OUTPUT
--Try to read the optional read from configuration file:
SET @readFromConfigFile = dbo.ConvertToInt(@parameter_value, 1, 0)
--Try and get the optional logging level for the DatabaseMail process
EXEC msdb.dbo.sysmail_help_configure_value_sp @parameter_name = N'LoggingLevel',
@parameter_value = @loggingLevel OUTPUT
--Convert logging level into string value for passing into XP
SET @loggingLevelInt = dbo.ConvertToInt(@loggingLevel, 3, 2)
IF @loggingLevelInt = 1
SET @loggingLevel = 'Normal'
ELSE IF @loggingLevelInt = 3
SET @loggingLevel = 'Verbose'
ELSE -- default
SET @loggingLevel = 'Extended'
SET @mailDbName = DB_NAME()
SET @mailDbId = DB_ID()
EXEC @rc = master..xp_sysmail_activate @mailDbId, @mailDbName, @readFromConfigFile,
@mailEngineLifeMin, @loggingLevel
IF(@rc <> 0)
BEGIN
SET @localmessage = FORMATMESSAGE(14637)
exec msdb.dbo.sysmail_logmailevent_sp @event_type=3, @description=@localmessage
END
ELSE
BEGIN
SET @localmessage = FORMATMESSAGE(14638)
exec msdb.dbo.sysmail_logmailevent_sp @event_type=0, @description=@localmessage
END
RETURN @rc
END
GO
--------------------------------------------------------------
-- Database Mail roles and permissions
--------------------------------------------------------------
-- Create the DatabaseMailUserRole role
IF (EXISTS (SELECT *
FROM msdb.dbo.sysusers
WHERE (name = N'DatabaseMailUserRole')
AND (issqlrole = 1)))
BEGIN
-- If there are no members in the role, then drop and re-create it
IF ((SELECT COUNT(*)
FROM msdb.dbo.sysusers su,
msdb.dbo.sysmembers sm
WHERE (su.uid = sm.groupuid)
AND (su.name = N'DatabaseMailUserRole')
AND (su.issqlrole = 1)) = 0)
BEGIN
EXECUTE msdb.dbo.sp_droprole @rolename = N'DatabaseMailUserRole'
EXECUTE msdb.dbo.sp_addrole @rolename = N'DatabaseMailUserRole'
END
END
ELSE
EXECUTE msdb.dbo.sp_addrole @rolename = N'DatabaseMailUserRole'
go
GRANT EXECUTE ON [dbo].[sp_send_dbmail] TO DatabaseMailUserRole
GRANT EXECUTE ON [dbo].[sysmail_help_status_sp] TO DatabaseMailUserRole
GRANT EXECUTE ON [dbo].[sysmail_delete_mailitems_sp] TO DatabaseMailUserRole
GRANT SELECT ON [dbo].[sysmail_allitems] TO DatabaseMailUserRole
GRANT SELECT ON [dbo].[sysmail_sentitems] TO DatabaseMailUserRole
GRANT SELECT ON [dbo].[sysmail_unsentitems] TO DatabaseMailUserRole
GRANT SELECT ON [dbo].[sysmail_faileditems] TO DatabaseMailUserRole
GRANT SELECT ON [dbo].[sysmail_mailattachments] TO DatabaseMailUserRole
GRANT SELECT ON [dbo].[sysmail_event_log] TO DatabaseMailUserRole
go
/*************************************************************************/
/* */
/* Database Mail SSB objects (Messages, Contracts, Queues, Services) */
/* */
/*************************************************************************/
PRINT ''
PRINT 'Dropping Database Mail MESSAGES, CONTRACTS, QUEUES AND SERVICES...'
PRINT ''
-- Drop service InternalMailService if existing.
IF EXISTS (SELECT * FROM sys.services WHERE name ='InternalMailService')
BEGIN
PRINT 'Dropping SERVICE InternalMailService'
DROP SERVICE InternalMailService;
END
-- Drop service ExternalMailService if existing.
IF EXISTS (SELECT * FROM sys.services WHERE name ='ExternalMailService')
BEGIN
PRINT 'Dropping SERVICE ExternalMailService'
DROP SERVICE ExternalMailService;
END
-- Drop queue InternalMailQueue if existing.
IF EXISTS (SELECT * FROM sys.objects WHERE name = 'InternalMailQueue' AND type = 'SQ')
BEGIN
PRINT 'Dropping QUEUE InternalMailQueue'
DROP QUEUE InternalMailQueue;
END
-- Drop queue ExternalMailQueue if existing.
IF EXISTS (SELECT * FROM sys.objects WHERE name = 'ExternalMailQueue' AND type = 'SQ')
BEGIN
PRINT 'Dropping QUEUE ExternalMailQueue'
DROP QUEUE ExternalMailQueue;
END
--Drop Notification service for activation of DatabaseMail.exe
IF EXISTS (SELECT * FROM sys.services WHERE name ='SQL/Notifications/SysMailNotification/v1.0')
BEGIN
PRINT 'Dropping SERVICE [SQL/Notifications/SysMailNotification/v1.0]'
DROP SERVICE [SQL/Notifications/SysMailNotification/v1.0];
END
--Drop SysMailNotificationQueue if existing
IF EXISTS (SELECT * FROM sys.objects WHERE name = 'SysMailNotificationQueue' AND type = 'SQ')
BEGIN
PRINT 'Dropping QUEUE SysMailNotificationQueue'
DROP QUEUE SysMailNotificationQueue;
END
-- Drop SendMail v1.0 contract if existing.
IF EXISTS(SELECT * FROM sys.service_contracts
WHERE name = '//www.microsoft.com/databasemail/contracts/SendMail/v1.0')
BEGIN
PRINT 'Dropping CONTRACT [//www.microsoft.com/databasemail/contracts/SendMail/v1.0]'
DROP CONTRACT [//www.microsoft.com/databasemail/contracts/SendMail/v1.0];
END
-- Drop SendMail message type if existing.
IF EXISTS(SELECT * FROM sys.service_message_types
WHERE name = '{//www.microsoft.com/databasemail/messages}SendMail')
BEGIN
PRINT 'Dropping MESSAGE TYPE [{//www.microsoft.com/databasemail/messages}SendMail]'
DROP MESSAGE TYPE [{//www.microsoft.com/databasemail/messages}SendMail];
END
-- Drop SendMailStatus message type if existing.
IF EXISTS(SELECT * FROM sys.service_message_types
WHERE name = '{//www.microsoft.com/databasemail/messages}SendMailStatus')
BEGIN
PRINT 'Dropping MESSAGE TYPE [{//www.microsoft.com/databasemail/messages}SendMailStatus]'
DROP MESSAGE TYPE [{//www.microsoft.com/databasemail/messages}SendMailStatus];
END
GO
-------------------------------------------------------------------
-- Create Database Mail MESSAGES, CONTRACTS, QUEUES AND SERVICES
-------------------------------------------------------------------
PRINT ''
PRINT 'Creating MESSAGES, CONTRACTS, QUEUES AND SERVICES...'
PRINT ''
-- Create SendMail message type.
PRINT 'Creating MESSAGE TYPE [{//www.microsoft.com/databasemail/messages}SendMail]'
CREATE MESSAGE TYPE
[{//www.microsoft.com/databasemail/messages}SendMail]
VALIDATION = NONE
CREATE MESSAGE TYPE
[{//www.microsoft.com/databasemail/messages}SendMailStatus]
VALIDATION = NONE
-- Create SendMail contract.
PRINT 'Creating CONTRACT [//www.microsoft.com/databasemail/contracts/SendMail/v1.0]'
CREATE CONTRACT [//www.microsoft.com/databasemail/contracts/SendMail/v1.0]
(
[{//www.microsoft.com/databasemail/messages}SendMail] SENT BY INITIATOR,
[{//www.microsoft.com/databasemail/messages}SendMailStatus] SENT BY TARGET
)
-- Create InternalMailQueue queue.
PRINT 'Creating QUEUE InternalMailQueue'
CREATE QUEUE InternalMailQueue
WITH ACTIVATION (PROCEDURE_NAME = sp_ExternalMailQueueListener,
MAX_QUEUE_READERS = 1,
EXECUTE AS SELF);
-- Create ExternalMailQueue queue.
PRINT 'Creating QUEUE ExternalMailQueue'
CREATE QUEUE ExternalMailQueue
WITH ACTIVATION (PROCEDURE_NAME = sp_sysmail_activate,
MAX_QUEUE_READERS = 1,
EXECUTE AS SELF);
-- Create InternalMailService service.
PRINT 'Creating SERVICE InternalMailService ON QUEUE InternalMailQueue'
CREATE SERVICE InternalMailService ON QUEUE InternalMailQueue
(
[//www.microsoft.com/databasemail/contracts/SendMail/v1.0]
-- ,[//www.microsoft.com/databasemail/contracts/TestProfile/v1.0]
);
-- Create ExternalMailService service.
PRINT 'Creating SERVICE ExternalMailService ON QUEUE ExternalMailQueue'
CREATE SERVICE ExternalMailService ON QUEUE ExternalMailQueue
(
[//www.microsoft.com/databasemail/contracts/SendMail/v1.0]
-- ,[//www.microsoft.com/databasemail/contracts/TestProfile/v1.0]
);
GO
/**************************************************************/
/* */
/* M A I N T E N A N C E P L A N S */
/* */
/**************************************************************/
/**************************************************************/
/* sysmaintplan_subplans */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmaintplan_subplans')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysmaintplan_subplans...'
-- This table stores the DTS package associated with the maintenance plan
-- It also stored metadata about the maintenance plan such as its name, description etc
CREATE TABLE sysmaintplan_subplans
(
subplan_id UNIQUEIDENTIFIER NOT NULL
CONSTRAINT [PK_sysmaintplan_subplan] PRIMARY KEY CLUSTERED,
subplan_name sysname NOT NULL,
subplan_description NVARCHAR(512) NULL,
plan_id UNIQUEIDENTIFIER NOT NULL,
job_id UNIQUEIDENTIFIER NOT NULL
CONSTRAINT FK_subplan_job_id
FOREIGN KEY (job_id) REFERENCES sysjobs(job_id),
msx_job_id UNIQUEIDENTIFIER DEFAULT NULL NULL
CONSTRAINT FK_subplan_msx_job_id
FOREIGN KEY (msx_job_id) REFERENCES sysjobs(job_id),
schedule_id INT NULL
CONSTRAINT FK_subplan_schedule_id
FOREIGN KEY (schedule_id) REFERENCES sysschedules(schedule_id),
msx_plan bit DEFAULT 0 NOT NULL
)
END
go
/**************************************************************/
/* sysmaintplan_log */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmaintplan_log')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysmaintplan_log...'
-- This table stores the maintenance plan log info
CREATE TABLE sysmaintplan_log
(
task_detail_id UNIQUEIDENTIFIER NOT NULL
CONSTRAINT [PK_sysmaintplan_taskdetail_id] PRIMARY KEY CLUSTERED,
plan_id UNIQUEIDENTIFIER NULL,
subplan_id UNIQUEIDENTIFIER NULL
CONSTRAINT [FK_sysmaintplan_log_subplan_id]
FOREIGN KEY (subplan_id) REFERENCES sysmaintplan_subplans(subplan_id),
start_time DATETIME NULL,
end_time DATETIME NULL,
succeeded BIT NULL,
logged_remotely bit not null default (0),
source_server_name nvarchar (128) NULL,
plan_name nvarchar (128) NULL,
subplan_name nvarchar (128) NULL
)
END
go
/**************************************************************/
/* sysmaintplan_logdetail */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysmaintplan_logdetail')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysmaintplan_logdetail...'
-- This table stores the maintenance plan log details
CREATE TABLE sysmaintplan_logdetail
(
task_detail_id UNIQUEIDENTIFIER NOT NULL
CONSTRAINT [FK_sysmaintplan_log_detail_task_id]
FOREIGN KEY (task_detail_id) REFERENCES sysmaintplan_log(task_detail_id)
ON DELETE CASCADE,
line1 NVARCHAR(256) NOT NULL,
line2 NVARCHAR(256) NULL,
line3 NVARCHAR(256) NULL,
line4 NVARCHAR(256) NULL,
line5 NVARCHAR(256) NULL,
server_name sysname NOT NULL,
start_time DATETIME NULL,
end_time DATETIME NULL,
error_number INT NULL,
error_message NVARCHAR(max) NULL,
command NVARCHAR(max) NULL,
succeeded BIT NULL
)
END
go
/**************************************************************/
/* */
/* M A I N T E N A N C E P L A N S */
/* */
/**************************************************************/
/**************************************************************/
/* sp_maintplan_delete_log */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_maintplan_delete_log...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_maintplan_delete_log')
AND (type = 'P')))
DROP PROCEDURE sp_maintplan_delete_log
go
CREATE PROCEDURE sp_maintplan_delete_log
@plan_id UNIQUEIDENTIFIER = NULL,
@subplan_id UNIQUEIDENTIFIER = NULL,
@oldest_time DATETIME = NULL
AS
BEGIN
-- @plan_id and @subplan_id must be both NULL or only one exclusively set
IF (@plan_id IS NOT NULL) AND (@subplan_id IS NOT NULL)
BEGIN
RAISERROR(12980, -1, -1, '@plan_id', '@subplan_id')
RETURN(1)
END
--Scenario 1: User wants to delete all logs
--Scenario 2: User wants to delete all logs older than X date
--Scenario 3: User wants to delete all logs for a given plan
--Scenario 4: User wants to delete all logs for a specific subplan
--Scenario 5: User wants to delete all logs for a given plan older than X date
--Scenario 6: User wants to delete all logs for a specific subplan older than X date
-- Special case 1: Delete all logs
IF (@plan_id IS NULL) AND (@subplan_id IS NULL) AND (@oldest_time IS NULL)
BEGIN
DELETE msdb.dbo.sysmaintplan_logdetail
DELETE msdb.dbo.sysmaintplan_log
RETURN (0)
END
DELETE msdb.dbo.sysmaintplan_log
WHERE ( task_detail_id in
(SELECT task_detail_id
FROM msdb.dbo.sysmaintplan_log
WHERE ((@plan_id IS NULL) OR (plan_id = @plan_id)) AND
((@subplan_id IS NULL) OR (subplan_id = @subplan_id)) AND
((@oldest_time IS NULL) OR (start_time < @oldest_time))) )
RETURN (0)
END
GO
/**************************************************************/
/* sp_maintplan_delete_subplan */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_maintplan_delete_subplan...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_maintplan_delete_subplan')
AND (type = 'P')))
DROP PROCEDURE sp_maintplan_delete_subplan
go
CREATE PROCEDURE sp_maintplan_delete_subplan
@subplan_id UNIQUEIDENTIFIER,
@delete_jobs BIT = 1
AS
BEGIN
DECLARE @retval INT
DECLARE @job UNIQUEIDENTIFIER
DECLARE @jobMsx UNIQUEIDENTIFIER
SET NOCOUNT ON
SET @retval = 0
-- Raise an error if the @subplan_id doesn't exist
IF( NOT EXISTS(SELECT * FROM sysmaintplan_subplans WHERE subplan_id = @subplan_id))
BEGIN
DECLARE @subplan_id_as_char VARCHAR(36)
SELECT @subplan_id_as_char = CONVERT(VARCHAR(36), @subplan_id)
RAISERROR(14262, -1, -1, '@subplan_id', @subplan_id_as_char)
RETURN(1)
END
BEGIN TRAN
--Is there an Agent Job/Schedule associated with this subplan?
SELECT @job = job_id, @jobMsx = msx_job_id
FROM msdb.dbo.sysmaintplan_subplans
WHERE subplan_id = @subplan_id
EXEC @retval = msdb.dbo.sp_maintplan_delete_log @subplan_id = @subplan_id
IF (@retval <> 0)
BEGIN
ROLLBACK TRAN
RETURN @retval
END
-- Delete the subplans table entry first since it has a foreign
-- key constraint on its job_id existing in sysjobs.
DELETE msdb.dbo.sysmaintplan_subplans
WHERE (subplan_id = @subplan_id)
IF (@delete_jobs = 1)
BEGIN
--delete the local job associated with this subplan
IF (@job IS NOT NULL)
BEGIN
EXEC @retval = msdb.dbo.sp_delete_job @job_id = @job, @delete_unused_schedule = 1
IF (@retval <> 0)
BEGIN
ROLLBACK TRAN
RETURN @retval
END
END
--delete the multi-server job associated with this subplan.
IF (@jobMsx IS NOT NULL)
BEGIN
EXEC @retval = msdb.dbo.sp_delete_job @job_id = @jobMsx, @delete_unused_schedule = 1
IF (@retval <> 0)
BEGIN
ROLLBACK TRAN
RETURN @retval
END
END
END
COMMIT TRAN
RETURN (0)
END
go
/**************************************************************/
/* SP_MAINTPLAN_UPDATE_SUBPLAN_TSX */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_maintplan_update_subplan_tsx...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_maintplan_update_subplan_tsx')
AND (type = 'P')))
DROP PROCEDURE sp_maintplan_update_subplan_tsx
go
-- This procedure is called when a maintenance plan subplan record
-- needs to be created or updated to match a multi-server Agent job
-- that has arrived from the master server.
CREATE PROCEDURE sp_maintplan_update_subplan_tsx
@subplan_id UNIQUEIDENTIFIER,
@plan_id UNIQUEIDENTIFIER,
@name sysname,
@description NVARCHAR(512),
@job_id UNIQUEIDENTIFIER
AS
BEGIN
-- Find out what schedule, if any, is associated with the job.
declare @schedule_id int
select @schedule_id = (SELECT TOP(1) schedule_id
FROM msdb.dbo.sysjobschedules
WHERE (job_id = @job_id) )
exec sp_maintplan_update_subplan @subplan_id, @plan_id, @name, @description, @job_id, @schedule_id, @allow_create=1
-- Be sure to mark this subplan as coming from the master, not locally.
update sysmaintplan_subplans
set msx_plan = 1
where subplan_id = @subplan_id
END
go
/**************************************************************/
/* SP_MAINTPLAN_SUBPLANS_BY_JOB */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_maintplan_subplans_by_job...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_maintplan_subplans_by_job')
AND (type = 'P')))
DROP PROCEDURE sp_maintplan_subplans_by_job
go
-- If the given job_id is associated with a maintenance plan,
-- then matching entries from sysmaintplan_subplans are returned.
CREATE PROCEDURE sp_maintplan_subplans_by_job
@job_id UNIQUEIDENTIFIER
AS
BEGIN
select plans.name as 'plan_name', plans.id as 'plan_id', subplans.subplan_name, subplans.subplan_id
from sysmaintplan_plans plans, sysmaintplan_subplans subplans
where plans.id = subplans.plan_id
and (job_id = @job_id
or msx_job_id = @job_id)
order by subplans.plan_id, subplans.subplan_id
END
go
/**************************************************************/
/* sp_maintplan_open_logentry */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_maintplan_open_logentry...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_maintplan_open_logentry')
AND (type = 'P')))
DROP PROCEDURE sp_maintplan_open_logentry
go
CREATE PROCEDURE sp_maintplan_open_logentry
@plan_id UNIQUEIDENTIFIER,
@subplan_id UNIQUEIDENTIFIER,
@start_time DATETIME = NULL,
@task_detail_id UNIQUEIDENTIFIER = NULL OUTPUT
AS
BEGIN
--Set defaults
IF (@start_time IS NULL)
BEGIN
SELECT @start_time = GETDATE()
END
SELECT @task_detail_id = NEWID()
--Insert a new record into sysmaintplan_log table
INSERT INTO msdb.dbo.sysmaintplan_log(task_detail_id, plan_id, subplan_id, start_time)
VALUES(@task_detail_id, @plan_id, @subplan_id, @start_time)
RETURN (@@ERROR)
END
GO
/**************************************************************/
/* sp_maintplan_close_logentry */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_maintplan_close_logentry...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_maintplan_close_logentry')
AND (type = 'P')))
DROP PROCEDURE sp_maintplan_close_logentry
go
CREATE PROCEDURE sp_maintplan_close_logentry
@task_detail_id UNIQUEIDENTIFIER,
@end_time DATETIME = NULL,
@succeeded TINYINT
AS
BEGIN
--Set defaults
IF (@end_time IS NULL)
BEGIN
SELECT @end_time = GETDATE()
END
-- Raise an error if the @task_detail_id doesn't exist
IF( NOT EXISTS(SELECT * FROM sysmaintplan_log WHERE (task_detail_id = @task_detail_id)))
BEGIN
DECLARE @task_detail_id_as_char VARCHAR(36)
SELECT @task_detail_id_as_char = CONVERT(VARCHAR(36), @task_detail_id)
RAISERROR(14262, -1, -1, '@task_detail_id', @task_detail_id_as_char)
RETURN(1)
END
UPDATE msdb.dbo.sysmaintplan_log
SET end_time = @end_time, succeeded = @succeeded
WHERE (task_detail_id = @task_detail_id)
RETURN (@@ERROR)
END
go
/**************************************************************/
/* sp_maintplan_update_log */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_maintplan_update_log...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_maintplan_update_log')
AND (type = 'P')))
DROP PROCEDURE sp_maintplan_update_log
go
CREATE PROCEDURE sp_maintplan_update_log
--Updates the log_details table
@task_detail_id UNIQUEIDENTIFIER, --Required
@Line1 NVARCHAR(256), --Required
@Line2 NVARCHAR(256) = NULL,
@Line3 NVARCHAR(256) = NULL,
@Line4 NVARCHAR(256) = NULL,
@Line5 NVARCHAR(256) = NULL,
@server_name sysname, --Required
@succeeded TINYINT, --Required
@start_time DATETIME, --Required
@end_time DATETIME, --Required
@error_number int=NULL,
@error_message NVARCHAR(max) = NULL,
@command NVARCHAR(max) = NULL
AS
BEGIN
--Prep strings
SET NOCOUNT ON
SELECT @Line1 = LTRIM(RTRIM(@Line1))
SELECT @Line2 = LTRIM(RTRIM(@Line2))
SELECT @Line3 = LTRIM(RTRIM(@Line3))
SELECT @Line4 = LTRIM(RTRIM(@Line4))
SELECT @Line5 = LTRIM(RTRIM(@Line5))
INSERT INTO msdb.dbo.sysmaintplan_logdetail(
task_detail_id,
line1,
line2,
line3,
line4,
line5,
server_name,
start_time,
end_time,
error_number,
error_message,
command,
succeeded)
VALUES(
@task_detail_id,
@Line1,
@Line2,
@Line3,
@Line4,
@Line5,
@server_name,
@start_time,
@end_time,
@error_number,
@error_message,
@command,
@succeeded)
RETURN (@@ERROR)
END
GO
/**************************************************************/
/* sp_maintplan_update_subplan */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_maintplan_update_subplan...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_maintplan_update_subplan')
AND (type = 'P')))
DROP PROCEDURE sp_maintplan_update_subplan
go
CREATE PROCEDURE sp_maintplan_update_subplan
@subplan_id UNIQUEIDENTIFIER,
@plan_id UNIQUEIDENTIFIER = NULL,
@name sysname = NULL,
@description NVARCHAR(512) = NULL,
@job_id UNIQUEIDENTIFIER = NULL,
@schedule_id INT = NULL,
@allow_create BIT = 0,
@msx_job_id UNIQUEIDENTIFIER = NULL
AS
BEGIN
SET NOCOUNT ON
SELECT @name = LTRIM(RTRIM(@name))
SELECT @description = LTRIM(RTRIM(@description))
--Are we creating a new entry or updating an existing one?
IF( NOT EXISTS(SELECT * FROM msdb.dbo.sysmaintplan_subplans WHERE subplan_id = @subplan_id) )
BEGIN
-- Only allow creation of a record if user permits it
IF(@allow_create = 0)
BEGIN
DECLARE @subplan_id_as_char VARCHAR(36)
SELECT @subplan_id_as_char = CONVERT(VARCHAR(36), @subplan_id)
RAISERROR(14262, -1, -1, '@subplan_id', @subplan_id_as_char)
RETURN(1)
END
--Insert it's a new subplan
IF (@name IS NULL)
BEGIN
RAISERROR(12981, -1, -1, '@name')
RETURN(1) -- Failure
END
IF (@plan_id IS NULL)
BEGIN
RAISERROR(12981, -1, -1, '@plan_id')
RETURN(1) -- Failure
END
INSERT INTO msdb.dbo.sysmaintplan_subplans(
subplan_id,
plan_id,
subplan_description,
subplan_name,
job_id,
schedule_id,
msx_job_id)
VALUES(
@subplan_id,
@plan_id,
@description,
@name,
@job_id,
@schedule_id,
@msx_job_id)
END
ELSE
BEGIN --Update the table
DECLARE @s_subplan_name sysname
DECLARE @s_job_id UNIQUEIDENTIFIER
SELECT @s_subplan_name = subplan_name,
@s_job_id = job_id
FROM msdb.dbo.sysmaintplan_subplans
WHERE (@subplan_id = subplan_id)
--Determine if user wants to change these variables
IF (@name IS NOT NULL) SELECT @s_subplan_name = @name
IF (@job_id IS NOT NULL) SELECT @s_job_id = @job_id
--UPDATE the record
UPDATE msdb.dbo.sysmaintplan_subplans
SET subplan_name = @s_subplan_name,
subplan_description = @description,
job_id = @s_job_id,
schedule_id = @schedule_id,
msx_job_id = @msx_job_id
WHERE (subplan_id = @subplan_id)
END
RETURN (@@ERROR)
END
GO
/**************************************************************/
/* sp_maintplan_delete_plan */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_maintplan_delete_plan...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_maintplan_delete_plan')
AND (type = 'P')))
DROP PROCEDURE sp_maintplan_delete_plan
go
CREATE PROCEDURE sp_maintplan_delete_plan
@plan_id UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
DECLARE @sp_id UNIQUEIDENTIFIER
DECLARE @retval INT
SET @retval = 0
--Loop through Subplans
DECLARE sp CURSOR LOCAL FOR
SELECT subplan_id
FROM msdb.dbo.sysmaintplan_subplans
WHERE plan_id = @plan_id FOR READ ONLY
OPEN sp
FETCH NEXT FROM sp INTO @sp_id
WHILE @@FETCH_STATUS = 0
BEGIN
EXECUTE @retval = sp_maintplan_delete_subplan @subplan_id = @sp_id
IF(@retval <> 0)
BREAK
FETCH NEXT FROM sp INTO @sp_id
END
CLOSE sp
DEALLOCATE sp
RETURN (@retval)
END
go
/**************************************************************/
/* sp_maintplan_start */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_maintplan_start...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_maintplan_start')
AND (type = 'P')))
DROP PROCEDURE sp_maintplan_start
go
CREATE PROCEDURE sp_maintplan_start
@plan_id UNIQUEIDENTIFIER = NULL,
@subplan_id UNIQUEIDENTIFIER = NULL
AS
BEGIN
SET NOCOUNT ON
DECLARE @jobid UNIQUEIDENTIFIER
DECLARE @retval INT
SET @retval = 0
-- A @plan_id or @subplan_id must be supplied
IF (@plan_id IS NULL) AND (@subplan_id IS NULL)
BEGIN
RAISERROR(12982, -1, -1, '@plan_id', '@subplan_id')
RETURN(1)
END
-- either @plan_id or @subplan_id must be exclusively set
IF (@plan_id IS NOT NULL) AND (@subplan_id IS NOT NULL)
BEGIN
RAISERROR(12982, -1, -1, '@plan_id', '@subplan_id')
RETURN(1)
END
IF (@subplan_id IS NOT NULL)
BEGIN
-- subplan_id supplied so simply start the subplan's job
SELECT @jobid = job_id
FROM msdb.dbo.sysmaintplan_subplans
WHERE subplan_id = @subplan_id
if(@jobid IS NOT NULL)
BEGIN
EXEC @retval = msdb.dbo.sp_start_job @job_id = @jobid
END
END
ELSE
BEGIN
-- Loop through Subplans and fire off all associated jobs
DECLARE spj CURSOR LOCAL FOR
SELECT job_id
FROM msdb.dbo.sysmaintplan_subplans
WHERE plan_id = @plan_id FOR READ ONLY
OPEN spj
FETCH NEXT FROM spj INTO @jobid
WHILE (@@FETCH_STATUS = 0)
BEGIN
EXEC @retval = msdb.dbo.sp_start_job @job_id = @jobid
IF(@retval <> 0)
BREAK
FETCH NEXT FROM spj INTO @jobid
END
CLOSE spj
DEALLOCATE spj
END
RETURN (@retval)
END
GO
/**************************************************************/
/* sp_get_script */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_get_script...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_get_script')
AND (type = 'P')))
DROP PROCEDURE sp_get_script
go
CREATE PROCEDURE sp_get_script
@name sysname
AS
BEGIN
exec master.dbo.xp_get_script @name
END
GO
/*==================================================================*/
--TODO: The following SYSDBMAINT... tables and SP's will be removed
/*==================================================================*/
/**************************************************************/
/* SYSDBMAINTPLANS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysdbmaintplans')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysdbmaintplans...'
CREATE TABLE sysdbmaintplans
(
plan_id UNIQUEIDENTIFIER NOT NULL PRIMARY KEY CLUSTERED,
plan_name sysname NOT NULL,
date_created DATETIME NOT NULL DEFAULT (GETDATE()),
owner sysname NOT NULL DEFAULT (ISNULL(NT_CLIENT(), SUSER_SNAME())),
max_history_rows INT NOT NULL DEFAULT (0),
remote_history_server sysname NOT NULL DEFAULT (''),
max_remote_history_rows INT NOT NULL DEFAULT (0),
user_defined_1 INT NULL,
user_defined_2 NVARCHAR(100) NULL,
user_defined_3 DATETIME NULL,
user_defined_4 UNIQUEIDENTIFIER NULL
)
END
go
-- Add row for "plan 0"
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysdbmaintplans
WHERE (plan_id = CONVERT(UNIQUEIDENTIFIER, 0x00))))
INSERT INTO sysdbmaintplans(plan_id, plan_name, owner) VALUES (0x00, N'All ad-hoc plans', N'sa')
go
/**************************************************************/
/* SYSDBMAINTPLAN_JOBS */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysdbmaintplan_jobs')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysdbmaintplan_jobs...'
CREATE TABLE sysdbmaintplan_jobs
(
plan_id UNIQUEIDENTIFIER NOT NULL UNIQUE CLUSTERED (plan_id, job_id)
FOREIGN KEY REFERENCES msdb.dbo.sysdbmaintplans (plan_id),
job_id UNIQUEIDENTIFIER NOT NULL
)
END
go
/**************************************************************/
/* SYSDBMAINTPLAN_DATABASES */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysdbmaintplan_databases')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysdbmaintplan_databases...'
CREATE TABLE sysdbmaintplan_databases
(
plan_id UNIQUEIDENTIFIER NOT NULL UNIQUE CLUSTERED (plan_id, database_name)
FOREIGN KEY REFERENCES msdb.dbo.sysdbmaintplans (plan_id),
database_name sysname NOT NULL
)
END
go
/**************************************************************/
/* SYSDBMAINTPLAN_HISTORY */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sysdbmaintplan_history')
AND (type = 'U')))
BEGIN
PRINT ''
PRINT 'Creating table sysdbmaintplan_history...'
CREATE TABLE sysdbmaintplan_history
(
sequence_id INT NOT NULL IDENTITY UNIQUE NONCLUSTERED,
plan_id UNIQUEIDENTIFIER NOT NULL DEFAULT('00000000-0000-0000-0000-000000000000'),
plan_name sysname NOT NULL DEFAULT('All ad-hoc plans'),
database_name sysname NULL,
server_name sysname NOT NULL DEFAULT (CONVERT(sysname, ServerProperty('ServerName'))),
activity NVARCHAR(128) NULL,
succeeded BIT NOT NULL DEFAULT (1),
end_time DATETIME NOT NULL DEFAULT (GETDATE()),
duration INT NULL DEFAULT (0),
start_time AS DATEADD (ss, -duration, end_time),
error_number INT NOT NULL DEFAULT (0),
message NVARCHAR(512) NULL
)
CREATE CLUSTERED INDEX clust ON sysdbmaintplan_history(plan_id)
END
-- ALTER TABLE to correct default constraint
ELSE
BEGIN
DECLARE @t TABLE
(
constraint_type NVARCHAR(146) COLLATE database_default NULL,
constraint_name sysname COLLATE database_default NULL,
delete_action NVARCHAR(20) COLLATE database_default NULL,
update_action NVARCHAR(20) COLLATE database_default NULL,
status_enabled NVARCHAR(20) COLLATE database_default NULL,
status_for_replication NVARCHAR(20) COLLATE database_default NULL,
constraint_keys NVARCHAR(2126) COLLATE database_default NULL
)
INSERT INTO @t EXEC sp_helpconstraint N'sysdbmaintplan_history', 'nomsg'
DECLARE @constraint_name sysname
DECLARE @sql NVARCHAR(4000)
SELECT @constraint_name = constraint_name
FROM @t
WHERE constraint_type = N'DEFAULT on column server_name'
AND constraint_keys = N'(@@servername)'
-- default found
IF (@constraint_name IS NOT NULL)
BEGIN
PRINT ''
PRINT 'Alter sysdbmaintplan_history ...'
SELECT @sql = N'ALTER TABLE sysdbmaintplan_history DROP CONSTRAINT ' + QUOTENAME(@constraint_name)
EXEC (@sql)
ALTER TABLE sysdbmaintplan_history
ADD CONSTRAINT servername_default DEFAULT (CONVERT(sysname, ServerProperty('ServerName')))
FOR server_name
END
END
go
/**************************************************************/
/* SPs for the maintenance plans */
/**************************************************************/
/**************************************************************/
/* sp_clear_dbmaintplan_by_db */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_clear_dbmaintplan_by_db...'
GO
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_clear_dbmaintplan_by_db') AND (type = 'P')))
DROP PROCEDURE sp_clear_dbmaintplan_by_db
GO
CREATE PROCEDURE sp_clear_dbmaintplan_by_db
@db_name sysname
AS
BEGIN
DECLARE planid_cursor CURSOR
FOR
select plan_id from msdb.dbo.sysdbmaintplan_databases where database_name=@db_name
OPEN planid_cursor
declare @planid uniqueidentifier
FETCH NEXT FROM planid_cursor INTO @planid
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
delete from msdb.dbo.sysdbmaintplan_databases where plan_id=@planid AND database_name=@db_name
if (NOT EXISTS(select * from msdb.dbo.sysdbmaintplan_databases where plan_id=@planid))
BEGIN
--delete the job
DECLARE jobid_cursor CURSOR
FOR
select job_id from msdb.dbo.sysdbmaintplan_jobs where plan_id=@planid
OPEN jobid_cursor
DECLARE @jobid uniqueidentifier
FETCH NEXT FROM jobid_cursor INTO @jobid
WHILE (@@FETCH_STATUS <> -1)
BEGIN
if (@@FETCH_STATUS <> -2)
BEGIN
execute msdb.dbo.sp_delete_job @jobid
END
FETCH NEXT FROM jobid_cursor into @jobid
END
CLOSE jobid_cursor
DEALLOCATE jobid_cursor
--delete the history
delete from msdb.dbo.sysdbmaintplan_history where plan_id=@planid
--delete the plan
delete from msdb.dbo.sysdbmaintplans where plan_id=@planid
END
END
FETCH NEXT FROM planid_cursor INTO @planid
END
CLOSE planid_cursor
DEALLOCATE planid_cursor
END
GO
/**************************************************************/
/* sp_add_maintenance_plan */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_maintenance_plan...'
GO
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_maintenance_plan') AND (type = 'P')))
DROP PROCEDURE sp_add_maintenance_plan
GO
CREATE PROCEDURE sp_add_maintenance_plan
@plan_name varchar(128),
@plan_id UNIQUEIDENTIFIER OUTPUT
AS
BEGIN
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysdbmaintplans
WHERE plan_name=@plan_name))
BEGIN
SELECT @plan_id=NEWID()
INSERT INTO msdb.dbo.sysdbmaintplans (plan_id, plan_name) VALUES (@plan_id, @plan_name)
END
ELSE
BEGIN
RAISERROR(14261,-1,-1,'@plan_name',@plan_name)
RETURN(1) -- failure
END
END
GO
/**************************************************************/
/* sp_delete_maintenance_plan */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_maintenance_plan...'
GO
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_maintenance_plan')
AND (type = 'P')))
DROP PROCEDURE sp_delete_maintenance_plan
GO
CREATE PROCEDURE sp_delete_maintenance_plan
@plan_id UNIQUEIDENTIFIER
AS
BEGIN
/*check if the plan_id is valid*/
IF (NOT EXISTS(SELECT *
FROM sysdbmaintplans
WHERE plan_id=@plan_id))
BEGIN
DECLARE @syserr VARCHAR(100)
SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)
RAISERROR(14262,-1,-1,'@plan_id',@syserr)
RETURN(1)
END
/* clean the related records in sysdbmaintplan_database */
DELETE FROM msdb.dbo.sysdbmaintplan_databases
WHERE plan_id=@plan_id
/* clean the related records in sysdbmaintplan_jobs*/
DELETE FROM msdb.dbo.sysdbmaintplan_jobs
WHERE plan_id=@plan_id
/* clean sysdbmaintplans */
DELETE FROM msdb.dbo.sysdbmaintplans
WHERE plan_id= @plan_id
END
GO
/**************************************************************/
/* sp_add_maintenance_plan_db */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_maintenance_plan_db...'
GO
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_maintenance_plan_db')
AND (type = 'P')))
DROP PROCEDURE sp_add_maintenance_plan_db
GO
CREATE PROCEDURE sp_add_maintenance_plan_db
@plan_id UNIQUEIDENTIFIER,
@db_name sysname
AS
BEGIN
DECLARE @syserr VARCHAR(100)
/*check if the plan_id is valid */
IF (NOT EXISTS (SELECT plan_id
FROM msdb.dbo.sysdbmaintplans
WHERE plan_id=@plan_id))
BEGIN
SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)
RAISERROR(14262,-1,-1,'@plan_id',@syserr)
RETURN(1)
END
/*check if the database name is valid */
IF (NOT EXISTS (SELECT name
FROM master.dbo.sysdatabases
WHERE name=@db_name))
BEGIN
RAISERROR(14262,-1,-1,'@db_name',@db_name)
RETURN(1)
END
/*check if the (plan_id, database) pair already exists*/
IF (EXISTS (SELECT *
FROM sysdbmaintplan_databases
WHERE plan_id=@plan_id AND database_name=@db_name))
BEGIN
SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)+' + '+@db_name
RAISERROR(14261,-1,-1,'@plan_id+@db_name',@syserr)
RETURN(1)
END
INSERT INTO msdb.dbo.sysdbmaintplan_databases (plan_id,database_name) VALUES (@plan_id, @db_name)
END
GO
/**************************************************************/
/* sp_delete_maintenance_plan_db */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_maintenance_plan_db...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_maintenance_plan_db')
AND (type = 'P')))
DROP PROCEDURE sp_delete_maintenance_plan_db
go
CREATE PROCEDURE sp_delete_maintenance_plan_db
@plan_id uniqueidentifier,
@db_name sysname
AS
BEGIN
/*check if the (plan_id, db_name) exists in the table*/
IF (NOT EXISTS(SELECT *
FROM msdb.dbo.sysdbmaintplan_databases
WHERE @plan_id=plan_id AND @db_name=database_name))
BEGIN
DECLARE @syserr VARCHAR(300)
SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)+' + '+@db_name
RAISERROR(14262,-1,-1,'@plan_id+@db_name',@syserr)
RETURN(1)
END
/*delete the pair*/
DELETE FROM msdb.dbo.sysdbmaintplan_databases
WHERE plan_id=@plan_id AND database_name=@db_name
END
GO
/**************************************************************/
/* sp_add_maintenance_plan_job */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_maintenance_plan_job...'
GO
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_add_maintenance_plan_job')
AND (type = 'P')))
DROP PROCEDURE sp_add_maintenance_plan_job
GO
CREATE PROCEDURE sp_add_maintenance_plan_job
@plan_id UNIQUEIDENTIFIER,
@job_id UNIQUEIDENTIFIER
AS
BEGIN
DECLARE @syserr varchar(100)
/*check if the @plan_id is valid*/
IF (NOT EXISTS(SELECT plan_id
FROM msdb.dbo.sysdbmaintplans
WHERE plan_id=@plan_id))
BEGIN
SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)
RAISERROR(14262,-1,-1,'@plan_id',@syserr)
RETURN(1)
END
/*check if the @job_id is valid*/
IF (NOT EXISTS(SELECT job_id
FROM msdb.dbo.sysjobs
WHERE job_id=@job_id))
BEGIN
SELECT @syserr=CONVERT(VARCHAR(100),@job_id)
RAISERROR(14262,-1,-1,'@job_id',@syserr)
RETURN(1)
END
/*check if the job has at least one step calling xp_sqlmaint*/
DECLARE @maxind INT
SELECT @maxind=(SELECT MAX(CHARINDEX('xp_sqlmaint', command))
FROM msdb.dbo.sysjobsteps
WHERE @job_id=job_id)
IF (@maxind<=0)
BEGIN
/*print N'Warning: The job is not for maitenance plan.' -- will add the new sysmessage here*/
SELECT @syserr=CONVERT(VARCHAR(100),@job_id)
RAISERROR(14199,-1,-1,@syserr)
RETURN(1)
END
INSERT INTO msdb.dbo.sysdbmaintplan_jobs(plan_id,job_id) VALUES (@plan_id, @job_id) --don't have to check duplicate here
END
GO
/**************************************************************/
/* sp_delete_maintenance_plan_job */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_maintenance_plan_job...'
GO
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_maintenance_plan_job')
AND (type = 'P')))
DROP PROCEDURE sp_delete_maintenance_plan_job
GO
CREATE PROCEDURE sp_delete_maintenance_plan_job
@plan_id uniqueidentifier,
@job_id uniqueidentifier
AS
BEGIN
/*check if the (plan_id, job_id) exists*/
IF (NOT EXISTS(SELECT *
FROM sysdbmaintplan_jobs
WHERE @plan_id=plan_id AND @job_id=job_id))
BEGIN
DECLARE @syserr VARCHAR(300)
SELECT @syserr=CONVERT(VARCHAR(100),@plan_id)+' + '+CONVERT(VARCHAR(100),@job_id)
RAISERROR(14262,-1,-1,'@plan_id+@job_id',@syserr)
RETURN(1)
END
DELETE FROM msdb.dbo.sysdbmaintplan_jobs
WHERE plan_id=@plan_id AND job_id=@job_id
END
GO
/**************************************************************/
/* sp_help_maintenance_plan */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_help_maintenance_plan...'
GO
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_help_maintenance_plan')
AND (type = 'P')))
DROP PROCEDURE sp_help_maintenance_plan
GO
CREATE PROCEDURE sp_help_maintenance_plan
@plan_id UNIQUEIDENTIFIER = NULL
AS
BEGIN
IF (@plan_id IS NOT NULL)
BEGIN
/*return the information about the plan itself*/
SELECT *
FROM msdb.dbo.sysdbmaintplans
WHERE plan_id=@plan_id
/*return the information about databases this plan defined on*/
SELECT database_name
FROM msdb.dbo.sysdbmaintplan_databases
WHERE plan_id=@plan_id
/*return the information about the jobs that relating to the plan*/
SELECT job_id
FROM msdb.dbo.sysdbmaintplan_jobs
WHERE plan_id=@plan_id
END
ELSE
BEGIN
SELECT *
FROM msdb.dbo.sysdbmaintplans
END
END
GO
/**************************************************************/
/** **/
/** B A C K U P H I S T O R Y S U P P O R T **/
/** **/
/**************************************************************/
/**************************************************************/
/* T A B L E S */
/**************************************************************/
/**************************************************************/
/* BACKUPMEDIASET */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'backupmediaset')))
BEGIN
PRINT ''
PRINT 'Creating table backupmediaset...'
CREATE TABLE backupmediaset
(
media_set_id INT IDENTITY NOT NULL PRIMARY KEY,
media_uuid UNIQUEIDENTIFIER NULL, -- Null if this media set only one media family
media_family_count TINYINT NULL, -- Number of media families in the media set
name NVARCHAR(128) NULL,
description NVARCHAR(255) NULL,
software_name NVARCHAR(128) NULL,
software_vendor_id INT NULL,
MTF_major_version TINYINT NULL,
mirror_count TINYINT NULL, -- number of mirror plexes
is_password_protected BIT NULL,
is_compressed BIT NULL -- 1 if backup compression was used
)
CREATE INDEX backupmediasetuuid ON backupmediaset (media_uuid)
END
ELSE
BEGIN
IF EXISTS (
select * from msdb.dbo.syscolumns where name='password_protected' and id =
(select id from msdb.dbo.sysobjects where name='backupmediaset'))
ALTER TABLE backupmediaset DROP COLUMN password_protected
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='is_password_protected' and id =
(select id from msdb.dbo.sysobjects where name='backupmediaset'))
ALTER TABLE backupmediaset ADD is_password_protected BIT NULL
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='is_compressed' and id =
(select id from msdb.dbo.sysobjects where name='backupmediaset'))
ALTER TABLE backupmediaset ADD is_compressed BIT NULL
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='mirror_count' and id =
(select id from msdb.dbo.sysobjects where name='backupmediaset'))
ALTER TABLE backupmediaset ADD mirror_count TINYINT NULL
END
go
/**************************************************************/
/* BACKUPMEDIAFAMILY */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'backupmediafamily')))
BEGIN
PRINT ''
PRINT 'Creating table backupmediafamily...'
CREATE TABLE backupmediafamily
(
media_set_id INT NOT NULL REFERENCES backupmediaset(media_set_id),
family_sequence_number TINYINT NOT NULL, -- Raid sequence number
media_family_id UNIQUEIDENTIFIER NULL, -- This will be a uuid in MTF 2.0, allow space
media_count INT NULL, -- Number of media in the family
logical_device_name NVARCHAR(128) NULL, -- Name from sysdevices, if any
physical_device_name NVARCHAR(260) NULL, -- To facilitate restores from online media (disk)
device_type TINYINT NULL, -- Disk, tape, pipe, ...
physical_block_size INT NULL,
mirror TINYINT DEFAULT 0 NOT NULL
PRIMARY KEY (media_set_id, family_sequence_number, mirror)
)
CREATE INDEX backupmediafamilyuuid ON backupmediafamily (media_family_id)
END
ELSE
BEGIN
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='mirror' and id =
(select id from msdb.dbo.sysobjects where name='backupmediafamily'))
BEGIN
begin tran
-- remove any old constraint, not involving mirror
declare @pkName sysname
DECLARE @sql NVARCHAR(4000)
select @pkName=i.name
from
sys.indexes i,
sys.all_objects o
where
o.object_id = object_id ('backupmediafamily')
and o.object_id = i.object_id
and i.is_primary_key = 1
IF (@pkName IS NOT NULL)
begin
select @sql = N'ALTER TABLE backupmediafamily DROP CONSTRAINT ' + QUOTENAME(@pkName)
EXEC (@sql)
end
ALTER TABLE backupmediafamily ADD mirror TINYINT DEFAULT 0 NOT NULL
ALTER TABLE backupmediafamily ADD CONSTRAINT backupmediafamily_PK
PRIMARY KEY (media_set_id, family_sequence_number, mirror)
commit
END
END
go
/**************************************************************/
/* BACKUPSET - One row per backup operation. */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'backupset')))
BEGIN
PRINT ''
PRINT 'Creating table backupset...'
CREATE TABLE backupset
(
backup_set_id INT IDENTITY NOT NULL PRIMARY KEY,
backup_set_uuid UNIQUEIDENTIFIER NOT NULL,
media_set_id INT NOT NULL REFERENCES backupmediaset(media_set_id),
first_family_number TINYINT NULL, -- family number & media number of the media
first_media_number SMALLINT NULL, -- containing the start of this backup (first SSET)
last_family_number TINYINT NULL, -- family number & media number of the media
last_media_number SMALLINT NULL, -- containing the end of this backup (ESET after MBC)
catalog_family_number TINYINT NULL, -- family number & media number of the media
catalog_media_number SMALLINT NULL, -- containing the start of the 'directory' data stream
position INT NULL, -- For FILE=
expiration_date DATETIME NULL,
-- From SSET...
software_vendor_id INT NULL, -- Might want table for sw vendors
name NVARCHAR(128) NULL,
description NVARCHAR(255) NULL,
user_name NVARCHAR(128) NULL,
software_major_version TINYINT NULL,
software_minor_version TINYINT NULL,
software_build_version SMALLINT NULL,
time_zone SMALLINT NULL,
mtf_minor_version TINYINT NULL,
-- From CONFIG_INFO...
first_lsn NUMERIC(25,0) NULL,
last_lsn NUMERIC(25,0) NULL,
checkpoint_lsn NUMERIC(25,0) NULL,
database_backup_lsn NUMERIC(25,0) NULL,
database_creation_date DATETIME NULL,
backup_start_date DATETIME NULL,
backup_finish_date DATETIME NULL,
type CHAR(1) NULL,
sort_order SMALLINT NULL,
code_page SMALLINT NULL,
compatibility_level TINYINT NULL,
database_version INT NULL,
backup_size NUMERIC(20,0) NULL,
database_name NVARCHAR(128) NULL,
server_name NVARCHAR(128) NULL,
machine_name NVARCHAR(128) NULL,
flags INT NULL,
unicode_locale INT NULL,
unicode_compare_style INT NULL,
collation_name NVARCHAR(128) NULL,
is_password_protected BIT NULL,
recovery_model NVARCHAR(60) NULL,
has_bulk_logged_data BIT NULL,
is_snapshot BIT NULL,
is_readonly BIT NULL,
is_single_user BIT NULL,
has_backup_checksums BIT NULL,
is_damaged BIT NULL,
begins_log_chain BIT NULL,
has_incomplete_metadata BIT NULL,
is_force_offline BIT NULL,
is_copy_only BIT NULL,
first_recovery_fork_guid UNIQUEIDENTIFIER NULL,
last_recovery_fork_guid UNIQUEIDENTIFIER NULL,
fork_point_lsn NUMERIC(25,0) NULL,
database_guid UNIQUEIDENTIFIER NULL,
family_guid UNIQUEIDENTIFIER NULL,
differential_base_lsn NUMERIC(25,0) NULL,
differential_base_guid UNIQUEIDENTIFIER NULL,
compressed_backup_size NUMERIC(20,0) NULL
)
CREATE INDEX backupsetuuid ON backupset (backup_set_uuid)
CREATE INDEX backupsetDate ON backupset (backup_finish_date) -- helps sp_delete_backuphistory
END
ELSE
BEGIN
IF EXISTS (
select * from msdb.dbo.syscolumns where name='password_protected' and id =
(select id from msdb.dbo.sysobjects where name='backupset'))
ALTER TABLE backupset DROP COLUMN password_protected
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='flags' and id =
(select id from msdb.dbo.sysobjects where name='backupset'))
ALTER TABLE backupset ADD flags INT NULL
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='collation_name' and id =
(select id from msdb.dbo.sysobjects where name='backupset'))
ALTER TABLE backupset ADD
unicode_locale INT NULL,
unicode_compare_style INT NULL,
collation_name NVARCHAR(128) NULL
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='is_password_protected' and id =
(select id from msdb.dbo.sysobjects where name='backupset'))
ALTER TABLE backupset ADD is_password_protected BIT NULL
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='compressed_backup_size' and id =
(select id from msdb.dbo.sysobjects where name='backupset'))
ALTER TABLE backupset ADD compressed_backup_size NUMERIC(20,0) NULL
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='recovery_model' and id =
(select id from msdb.dbo.sysobjects where name='backupset'))
ALTER TABLE backupset ADD
recovery_model NVARCHAR(60) NULL,
has_bulk_logged_data BIT NULL,
is_snapshot BIT NULL,
is_readonly BIT NULL,
is_single_user BIT NULL,
has_backup_checksums BIT NULL,
is_damaged BIT NULL,
begins_log_chain BIT NULL,
has_incomplete_metadata BIT NULL,
is_force_offline BIT NULL,
is_copy_only BIT NULL,
first_recovery_fork_guid UNIQUEIDENTIFIER NULL,
last_recovery_fork_guid UNIQUEIDENTIFIER NULL,
fork_point_lsn NUMERIC(25,0) NULL,
database_guid UNIQUEIDENTIFIER NULL,
family_guid UNIQUEIDENTIFIER NULL,
differential_base_lsn NUMERIC(25,0) NULL,
differential_base_guid UNIQUEIDENTIFIER NULL
IF NOT EXISTS (
SELECT *
FROM msdb.sys.indexes
WHERE (name = 'backupsetDate'))
CREATE INDEX backupsetDate ON backupset (backup_finish_date)
END
go
/**************************************************************/
-- BACKUPFILE/FILEGROUP
-- One row per file/filegroup backed up
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'backupfilegroup')))
BEGIN
PRINT ''
PRINT 'Creating table backupfilegroup...'
CREATE TABLE backupfilegroup
(
backup_set_id INT NOT NULL REFERENCES backupset(backup_set_id),
name NVARCHAR(128) NOT NULL,
filegroup_id INT NOT NULL,
filegroup_guid UNIQUEIDENTIFIER NULL,
type CHAR(2) NOT NULL,
type_desc NVARCHAR(60) NOT NULL,
is_default BIT NOT NULL,
is_readonly BIT NOT NULL,
log_filegroup_guid UNIQUEIDENTIFIER NULL
PRIMARY KEY (backup_set_id, filegroup_id)
)
END
go
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'backupfile')))
BEGIN
PRINT ''
PRINT 'Creating table backupfile...'
CREATE TABLE backupfile
(
backup_set_id INT NOT NULL REFERENCES backupset(backup_set_id),
first_family_number TINYINT NULL, -- Family number & media number of he first media
first_media_number SMALLINT NULL, -- containing this file
filegroup_name NVARCHAR(128) NULL,
page_size INT NULL,
file_number NUMERIC(10,0) NOT NULL,
backed_up_page_count NUMERIC(10,0) NULL,
file_type CHAR(1) NULL, -- database or log
source_file_block_size NUMERIC(10,0) NULL,
file_size NUMERIC(20,0) NULL,
logical_name NVARCHAR(128) NULL,
physical_drive NVARCHAR(260) NULL, -- Drive or partition name
physical_name NVARCHAR(260) NULL, -- Remainder of physical (OS) filename
state TINYINT NULL,
state_desc NVARCHAR(64) NULL,
create_lsn NUMERIC(25,0) NULL,
drop_lsn NUMERIC(25,0) NULL,
file_guid UNIQUEIDENTIFIER NULL,
read_only_lsn NUMERIC(25,0) NULL,
read_write_lsn NUMERIC(25,0) NULL,
differential_base_lsn NUMERIC(25,0) NULL,
differential_base_guid UNIQUEIDENTIFIER NULL,
backup_size NUMERIC(20,0) NULL,
filegroup_guid UNIQUEIDENTIFIER NULL,
is_readonly BIT NULL,
is_present BIT NULL
PRIMARY KEY (backup_set_id, file_number)
)
END
ELSE
BEGIN
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='state' and id =
(select id from msdb.dbo.sysobjects where name='backupfile'))
BEGIN
-- we want NVARCHAR instead of VARCHAR
ALTER TABLE backupfile ALTER COLUMN
physical_drive NVARCHAR(260) NULL
ALTER TABLE backupfile ALTER COLUMN
physical_name NVARCHAR(260) NULL
ALTER TABLE backupfile ADD
state TINYINT NULL,
state_desc NVARCHAR(64) NULL,
create_lsn NUMERIC(25,0) NULL,
drop_lsn NUMERIC(25,0) NULL,
file_guid UNIQUEIDENTIFIER NULL,
read_only_lsn NUMERIC(25,0) NULL,
read_write_lsn NUMERIC(25,0) NULL,
differential_base_lsn NUMERIC(25,0) NULL,
differential_base_guid UNIQUEIDENTIFIER NULL,
backup_size NUMERIC(20,0) NULL,
filegroup_guid UNIQUEIDENTIFIER NULL,
is_readonly BIT NULL,
is_present BIT NULL
END
END
go
/**************************************************************/
/* RESTOREHISTORY - One row per restore operation. */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'restorehistory')))
BEGIN
PRINT ''
PRINT 'Creating table restorehistory...'
CREATE TABLE restorehistory
(
restore_history_id INT NOT NULL IDENTITY PRIMARY KEY,
restore_date DATETIME NULL,
destination_database_name NVARCHAR(128) NULL,
user_name NVARCHAR(128) NULL,
backup_set_id INT NOT NULL REFERENCES backupset(backup_set_id), -- The backup set restored
restore_type CHAR(1) NULL, -- Database, file, filegroup, log, verifyonly, ...
-- Various options...
replace BIT NULL, -- Replace(1), Noreplace(0)
recovery BIT NULL, -- Recovery(1), Norecovery(0)
restart BIT NULL, -- Restart(1), Norestart(0)
stop_at DATETIME NULL,
device_count TINYINT NULL, -- Can be less than number of media families
stop_at_mark_name NVARCHAR(128) NULL,
stop_before BIT NULL
)
CREATE INDEX restorehistorybackupset ON restorehistory (backup_set_id)
END
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.syscolumns
WHERE (name in ('stop_at_mark_name', 'stop_before'))
AND (id = (SELECT id
FROM msdb.dbo.sysobjects
WHERE (name = 'restorehistory')))))
BEGIN
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='stop_before' and id =
(select id from msdb.dbo.sysobjects where name='restorehistory'))
BEGIN
PRINT ''
PRINT 'Adding columns to table restorehistory...'
ALTER TABLE restorehistory
ADD
stop_at_mark_name NVARCHAR(128) NULL,
stop_before BIT NULL
END
END
go
/**************************************************************/
/* RESTOREFILE - One row per file restored. */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'restorefile')))
BEGIN
PRINT ''
PRINT 'Creating table restorefile...'
CREATE TABLE restorefile
(
restore_history_id INT NOT NULL REFERENCES restorehistory(restore_history_id),
file_number NUMERIC(10,0) NULL, -- Note: requires database to make unique
destination_phys_drive NVARCHAR(260) NULL,
destination_phys_name NVARCHAR(260) NULL
)
END
ELSE
BEGIN
ALTER TABLE restorefile ALTER COLUMN
destination_phys_drive NVARCHAR(260) NULL
ALTER TABLE restorefile ALTER COLUMN
destination_phys_name NVARCHAR(260) NULL
END
go
/**************************************************************/
/* RESTOREFILEGROUP - One row per filegroup restored. */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'restorefilegroup')))
BEGIN
PRINT ''
PRINT 'Creating table restorefilegroup...'
CREATE TABLE restorefilegroup
(
restore_history_id INT NOT NULL REFERENCES restorehistory(restore_history_id),
filegroup_name NVARCHAR(128) NULL
)
END
go
/**************************************************************/
/* LOGMARKHISTORY - One row per log mark generated */
/**************************************************************/
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'logmarkhistory')))
BEGIN
PRINT ''
PRINT 'Creating table logmarkhistory...'
CREATE TABLE logmarkhistory
(
database_name NVARCHAR(128) NOT NULL,
mark_name NVARCHAR(128) NOT NULL,
description NVARCHAR(255) NULL,
user_name NVARCHAR(128) NOT NULL,
lsn NUMERIC(25,0) NOT NULL,
mark_time DATETIME NOT NULL
)
CREATE INDEX logmarkhistory1 ON logmarkhistory (database_name, mark_name)
CREATE INDEX logmarkhistory2 ON logmarkhistory (database_name, lsn)
END
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'trig_backupset_delete')
AND (OBJECTPROPERTY(id, 'IsTrigger') != 0)))
BEGIN
DROP TRIGGER trig_backupset_delete
END
go
CREATE TRIGGER trig_backupset_delete ON msdb.dbo.backupset FOR DELETE AS
BEGIN
DELETE FROM msdb.dbo.logmarkhistory from deleted
WHERE (msdb.dbo.logmarkhistory.database_name = deleted.database_name)
AND (msdb.dbo.logmarkhistory.lsn >= deleted.first_lsn)
AND (msdb.dbo.logmarkhistory.lsn < deleted.last_lsn)
END
go
/**************************************************************/
/* suspect_pages */
/**************************************************************/
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'badpagehistory')))
DROP TABLE badpagehistory
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'suspect_page_table')))
DROP TABLE suspect_page_table
go
IF (NOT EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = 'suspect_pages')))
BEGIN
PRINT ''
PRINT 'Creating table suspect_pages...'
CREATE TABLE suspect_pages
(
database_id INT NOT NULL,
file_id INT NOT NULL,
page_id bigint NOT NULL, -- we only use unsigned 32bits
event_type INT NOT NULL,
error_count INT NOT NULL,
last_update_date DATETIME NOT NULL DEFAULT GETDATE()
)
END
go
/**************************************************************/
/** **/
/** O B J E C T P E R M I S S I O N S **/
/** **/
/**************************************************************/
GRANT SELECT ON backupfile TO PUBLIC
GRANT SELECT ON backupmediafamily TO PUBLIC
GRANT SELECT ON backupmediaset TO PUBLIC
GRANT SELECT ON backupset TO PUBLIC
GRANT SELECT ON restorehistory TO PUBLIC
GRANT SELECT ON restorefile TO PUBLIC
GRANT SELECT ON restorefilegroup TO PUBLIC
GRANT SELECT ON logmarkhistory TO PUBLIC
GRANT SELECT ON suspect_pages TO PUBLIC
go
/**************************************************************/
/* */
/* B A C K U P H I S T O R Y */
/* */
/**************************************************************/
/**************************************************************/
/* sp_delete_database_backuphistory */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_database_backuphistory...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_database_backuphistory')
AND (type = 'P')))
DROP PROCEDURE sp_delete_database_backuphistory
go
CREATE PROCEDURE sp_delete_database_backuphistory
@database_name sysname
AS
BEGIN
SET NOCOUNT ON
DECLARE @backup_set_id TABLE (backup_set_id INT)
DECLARE @media_set_id TABLE (media_set_id INT)
DECLARE @restore_history_id TABLE (restore_history_id INT)
INSERT INTO @backup_set_id (backup_set_id)
SELECT DISTINCT backup_set_id
FROM msdb.dbo.backupset
WHERE database_name = @database_name
INSERT INTO @media_set_id (media_set_id)
SELECT DISTINCT media_set_id
FROM msdb.dbo.backupset
WHERE database_name = @database_name
INSERT INTO @restore_history_id (restore_history_id)
SELECT DISTINCT restore_history_id
FROM msdb.dbo.restorehistory
WHERE backup_set_id IN (SELECT backup_set_id
FROM @backup_set_id)
BEGIN TRANSACTION
DELETE FROM msdb.dbo.backupfile
WHERE backup_set_id IN (SELECT backup_set_id
FROM @backup_set_id)
IF (@@error > 0)
GOTO Quit
DELETE FROM msdb.dbo.backupfilegroup
WHERE backup_set_id IN (SELECT backup_set_id
FROM @backup_set_id)
IF (@@error > 0)
GOTO Quit
DELETE FROM msdb.dbo.restorefile
WHERE restore_history_id IN (SELECT restore_history_id
FROM @restore_history_id)
IF (@@error > 0)
GOTO Quit
DELETE FROM msdb.dbo.restorefilegroup
WHERE restore_history_id IN (SELECT restore_history_id
FROM @restore_history_id)
IF (@@error > 0)
GOTO Quit
DELETE FROM msdb.dbo.restorehistory
WHERE restore_history_id IN (SELECT restore_history_id
FROM @restore_history_id)
IF (@@error > 0)
GOTO Quit
DELETE FROM msdb.dbo.backupset
WHERE backup_set_id IN (SELECT backup_set_id
FROM @backup_set_id)
IF (@@error > 0)
GOTO Quit
DELETE msdb.dbo.backupmediafamily
FROM msdb.dbo.backupmediafamily bmf
WHERE bmf.media_set_id IN (SELECT media_set_id
FROM @media_set_id)
AND ((SELECT COUNT(*)
FROM msdb.dbo.backupset
WHERE media_set_id = bmf.media_set_id) = 0)
IF (@@error > 0)
GOTO Quit
DELETE msdb.dbo.backupmediaset
FROM msdb.dbo.backupmediaset bms
WHERE bms.media_set_id IN (SELECT media_set_id
FROM @media_set_id)
AND ((SELECT COUNT(*)
FROM msdb.dbo.backupset
WHERE media_set_id = bms.media_set_id) = 0)
IF (@@error > 0)
GOTO Quit
COMMIT TRANSACTION
RETURN
Quit:
ROLLBACK TRANSACTION
END
go
/**************************************************************/
/* SP_DELETE_BACKUPHISTORY */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_backuphistory...'
go
IF (EXISTS (SELECT *
FROM msdb.dbo.sysobjects
WHERE (name = N'sp_delete_backuphistory')
AND (type = 'P')))
DROP PROCEDURE sp_delete_backuphistory
go
CREATE PROCEDURE sp_delete_backuphistory
@oldest_date datetime
AS
BEGIN
SET NOCOUNT ON
DECLARE @backup_set_id TABLE (backup_set_id INT)
DECLARE @media_set_id TABLE (media_set_id INT)
DECLARE @restore_history_id TABLE (restore_history_id INT)
INSERT INTO @backup_set_id (backup_set_id)
SELECT DISTINCT backup_set_id
FROM msdb.dbo.backupset
WHERE backup_finish_date < @oldest_date
INSERT INTO @media_set_id (media_set_id)
SELECT DISTINCT media_set_id
FROM msdb.dbo.backupset
WHERE backup_finish_date < @oldest_date
INSERT INTO @restore_history_id (restore_history_id)
SELECT DISTINCT restore_history_id
FROM msdb.dbo.restorehistory
WHERE backup_set_id IN (SELECT backup_set_id
FROM @backup_set_id)
BEGIN TRANSACTION
DELETE FROM msdb.dbo.backupfile
WHERE backup_set_id IN (SELECT backup_set_id
FROM @backup_set_id)
IF (@@error > 0)
GOTO Quit
DELETE FROM msdb.dbo.backupfilegroup
WHERE backup_set_id IN (SELECT backup_set_id
FROM @backup_set_id)
IF (@@error > 0)
GOTO Quit
DELETE FROM msdb.dbo.restorefile
WHERE restore_history_id IN (SELECT restore_history_id
FROM @restore_history_id)
IF (@@error > 0)
GOTO Quit
DELETE FROM msdb.dbo.restorefilegroup
WHERE restore_history_id IN (SELECT restore_history_id
FROM @restore_history_id)
IF (@@error > 0)
GOTO Quit
DELETE FROM msdb.dbo.restorehistory
WHERE restore_history_id IN (SELECT restore_history_id
FROM @restore_history_id)
IF (@@error > 0)
GOTO Quit
DELETE FROM msdb.dbo.backupset
WHERE backup_set_id IN (SELECT backup_set_id
FROM @backup_set_id)
IF (@@error > 0)
GOTO Quit
DELETE msdb.dbo.backupmediafamily
FROM msdb.dbo.backupmediafamily bmf
WHERE bmf.media_set_id IN (SELECT media_set_id
FROM @media_set_id)
AND ((SELECT COUNT(*)
FROM msdb.dbo.backupset
WHERE media_set_id = bmf.media_set_id) = 0)
IF (@@error > 0)
GOTO Quit
DELETE msdb.dbo.backupmediaset
FROM msdb.dbo.backupmediaset bms
WHERE bms.media_set_id IN (SELECT media_set_id
FROM @media_set_id)
AND ((SELECT COUNT(*)
FROM msdb.dbo.backupset
WHERE media_set_id = bms.media_set_id) = 0)
IF (@@error > 0)
GOTO Quit
COMMIT TRANSACTION
RETURN
Quit:
ROLLBACK TRANSACTION
END
go
/**********************************************************************/
/* TABLE : log_shipping_primaries */
/* Populated on the monitor server */
/* */
/**********************************************************************/
IF (NOT EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE (TABLE_NAME = N'log_shipping_primaries')))
BEGIN
PRINT ''
PRINT 'Creating table log_shipping_primaries...'
CREATE TABLE log_shipping_primaries
(
primary_id INT IDENTITY NOT NULL PRIMARY KEY,
primary_server_name sysname NOT NULL,
primary_database_name sysname NOT NULL,
maintenance_plan_id UNIQUEIDENTIFIER NULL,
backup_threshold INT NOT NULL,
threshold_alert INT NOT NULL,
threshold_alert_enabled BIT NOT NULL, /* 1 = enabled, 0 = disabled */
last_backup_filename NVARCHAR(500) NULL,
last_updated DATETIME NULL,
planned_outage_start_time INT NOT NULL,
planned_outage_end_time INT NOT NULL,
planned_outage_weekday_mask INT NOT NULL,
source_directory NVARCHAR(500) NULL
)
END
ELSE
BEGIN
IF (NOT EXISTS (SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (TABLE_NAME = N'log_shipping_primaries')
AND (COLUMN_NAME = N'source_directory')))
BEGIN
PRINT ''
PRINT 'Adding columns to table log_shipping_primaries...'
ALTER TABLE log_shipping_primaries
ADD source_directory NVARCHAR(500) NULL
END
END
go
/**********************************************************************/
/* TABLE : log_shipping_secondaries */
/* Populated on the monitor server */
/* */
/**********************************************************************/
IF (NOT EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE (TABLE_NAME = N'log_shipping_secondaries')))
BEGIN
PRINT ''
PRINT 'Creating table log_shipping_secondaries...'
CREATE TABLE log_shipping_secondaries
(
primary_id INT FOREIGN KEY REFERENCES log_shipping_primaries (primary_id),
secondary_server_name sysname,
secondary_database_name sysname,
last_copied_filename NVARCHAR(500),
last_loaded_filename NVARCHAR(500),
last_copied_last_updated DATETIME,
last_loaded_last_updated DATETIME,
secondary_plan_id UNIQUEIDENTIFIER,
copy_enabled BIT,
load_enabled BIT, /* 1 = load enabled, 0 = load disabled */
out_of_sync_threshold INT,
threshold_alert INT,
threshold_alert_enabled BIT, /*1 = enabled, 0 = disabled */
planned_outage_start_time INT,
planned_outage_end_time INT,
planned_outage_weekday_mask INT,
allow_role_change BIT DEFAULT (0)
)
END
ELSE
BEGIN
IF (NOT EXISTS (SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (TABLE_NAME = N'log_shipping_secondaries')
AND (COLUMN_NAME = N'allow_role_change')))
BEGIN
PRINT ''
PRINT 'Adding columns to table log_shipping_secondaries...'
ALTER TABLE log_shipping_secondaries
ADD allow_role_change BIT DEFAULT (0)
END
END
go
/**************************************************************/
/* sp_add_log_shipping_monitor_jobs */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_log_shipping_monitor_jobs...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_add_log_shipping_monitor_jobs' AND type = N'P') )
drop procedure sp_add_log_shipping_monitor_jobs
go
CREATE PROCEDURE sp_add_log_shipping_monitor_jobs AS
BEGIN
SET NOCOUNT ON
BEGIN TRANSACTION
DECLARE @rv INT
DECLARE @backup_job_name sysname
SET @backup_job_name = N'Log Shipping Alert Job - Backup'
IF (NOT EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @backup_job_name))
BEGIN
EXECUTE @rv = msdb.dbo.sp_add_job @job_name = N'Log Shipping Alert Job - Backup'
IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
EXECUTE @rv = msdb.dbo.sp_add_jobstep
@job_name = N'Log Shipping Alert Job - Backup',
@step_id = 1,
@step_name = N'Log Shipping Alert - Backup',
@command = N'EXECUTE msdb.dbo.sp_log_shipping_monitor_backup',
@on_fail_action = 2,
@flags = 4,
@subsystem = N'TSQL',
@on_success_step_id = 0,
@on_success_action = 1,
@on_fail_step_id = 0
IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
EXECUTE @rv = msdb.dbo.sp_add_jobschedule
@job_name = @backup_job_name,
@freq_type = 4,
@freq_interval = 1,
@freq_subday_type = 0x4,
@freq_subday_interval = 1, -- run every minute
@freq_relative_interval = 0,
@name = @backup_job_name
IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
EXECUTE @rv = msdb.dbo.sp_add_jobserver @job_name = @backup_job_name, @server_name = NULL
IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
END
DECLARE @restore_job_name sysname
SET @restore_job_name = 'Log Shipping Alert Job - Restore'
IF (NOT EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @restore_job_name))
BEGIN
EXECUTE @rv = msdb.dbo.sp_add_job @job_name = @restore_job_name
IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
EXECUTE @rv = msdb.dbo.sp_add_jobstep
@job_name = @restore_job_name,
@step_id = 1,
@step_name = @restore_job_name,
@command = N'EXECUTE msdb.dbo.sp_log_shipping_monitor_restore',
@on_fail_action = 2,
@flags = 4,
@subsystem = N'TSQL',
@on_success_step_id = 0,
@on_success_action = 1,
@on_fail_step_id = 0
IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
EXECUTE @rv = msdb.dbo.sp_add_jobschedule
@job_name = @restore_job_name,
@freq_type = 4,
@freq_interval = 1,
@freq_subday_type = 0x4,
@freq_subday_interval = 1, -- run every minute
@freq_relative_interval = 0,
@name = @restore_job_name
IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
EXECUTE @rv = msdb.dbo.sp_add_jobserver @job_name = @restore_job_name, @server_name = NULL
IF (@@error <> 0 OR @rv <> 0) GOTO rollback_quit -- error
END
COMMIT TRANSACTION
RETURN
rollback_quit:
ROLLBACK TRANSACTION
END
go
/**************************************************************/
/* sp_add_log_shipping_primary */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_log_shipping_primary...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_add_log_shipping_primary' AND type = N'P'))
drop procedure sp_add_log_shipping_primary
go
CREATE PROCEDURE sp_add_log_shipping_primary
@primary_server_name sysname,
@primary_database_name sysname,
@maintenance_plan_id UNIQUEIDENTIFIER = NULL,
@backup_threshold INT = 60,
@threshold_alert INT = 14420,
@threshold_alert_enabled BIT = 1,
@planned_outage_start_time INT = 0,
@planned_outage_end_time INT = 0,
@planned_outage_weekday_mask INT = 0,
@primary_id INT = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON
IF EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name)
BEGIN
DECLARE @pair_name NVARCHAR
SELECT @pair_name = @primary_server_name + N'.' + @primary_database_name
RAISERROR (14261,16,1, N'primary_server_name.primary_database_name', @pair_name)
RETURN (1) -- error
END
INSERT INTO msdb.dbo.log_shipping_primaries (
primary_server_name,
primary_database_name,
maintenance_plan_id,
backup_threshold,
threshold_alert,
threshold_alert_enabled,
last_backup_filename,
last_updated,
planned_outage_start_time,
planned_outage_end_time,
planned_outage_weekday_mask,
source_directory)
VALUES (@primary_server_name,
@primary_database_name,
@maintenance_plan_id,
@backup_threshold,
@threshold_alert,
@threshold_alert_enabled,
N'first_file_000000000000.trn',
GETDATE (),
@planned_outage_start_time,
@planned_outage_end_time,
@planned_outage_weekday_mask,
NULL)
SELECT @primary_id = @@IDENTITY
EXECUTE msdb.dbo.sp_add_log_shipping_monitor_jobs
END
go
/**************************************************************/
/* sp_add_log_shipping_secondary */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_add_log_shipping_secondary...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_add_log_shipping_secondary' AND type = N'P'))
drop procedure sp_add_log_shipping_secondary
go
CREATE PROCEDURE sp_add_log_shipping_secondary
@primary_id INT,
@secondary_server_name sysname,
@secondary_database_name sysname,
@secondary_plan_id UNIQUEIDENTIFIER,
@copy_enabled BIT = 1,
@load_enabled BIT = 1,
@out_of_sync_threshold INT = 60,
@threshold_alert INT = 14421,
@threshold_alert_enabled BIT = 1,
@planned_outage_start_time INT = 0,
@planned_outage_end_time INT = 0,
@planned_outage_weekday_mask INT = 0,
@allow_role_change BIT = 0
AS
BEGIN
SET NOCOUNT ON
IF NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries where primary_id = @primary_id)
BEGIN
RAISERROR (14262, 16, 1, N'primary_id', N'msdb.dbo.log_shipping_primaries')
RETURN(1)
END
INSERT INTO msdb.dbo.log_shipping_secondaries (
primary_id,
secondary_server_name,
secondary_database_name,
last_copied_filename,
last_loaded_filename,
last_copied_last_updated,
last_loaded_last_updated,
secondary_plan_id,
copy_enabled,
load_enabled,
out_of_sync_threshold,
threshold_alert,
threshold_alert_enabled,
planned_outage_start_time,
planned_outage_end_time,
planned_outage_weekday_mask,
allow_role_change)
VALUES (@primary_id,
@secondary_server_name,
@secondary_database_name,
N'first_file_000000000000.trn',
N'first_file_000000000000.trn',
GETDATE (),
GETDATE (),
@secondary_plan_id,
@copy_enabled,
@load_enabled,
@out_of_sync_threshold,
@threshold_alert,
@threshold_alert_enabled,
@planned_outage_start_time,
@planned_outage_end_time,
@planned_outage_weekday_mask,
@allow_role_change)
END
go
/**************************************************************/
/* sp_delete_log_shipping_monitor_jobs */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_log_shipping_monitor_jobs...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_monitor_jobs' AND type = N'P') )
drop procedure sp_delete_log_shipping_monitor_jobs
go
CREATE PROCEDURE sp_delete_log_shipping_monitor_jobs AS
BEGIN
DECLARE @backup_job_name sysname
SET NOCOUNT ON
SET @backup_job_name = N'Log Shipping Alert Job - Backup'
IF (EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @backup_job_name))
EXECUTE msdb.dbo.sp_delete_job @job_name = N'Log Shipping Alert Job - Backup'
DECLARE @restore_job_name sysname
SET @restore_job_name = 'Log Shipping Alert Job - Restore'
IF (EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @restore_job_name))
EXECUTE msdb.dbo.sp_delete_job @job_name = N'Log Shipping Alert Job - Restore'
END
go
/**************************************************************/
/* sp_delete_log_shipping_primary */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_log_shipping_primary...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_primary' AND type = N'P') )
drop procedure sp_delete_log_shipping_primary
go
CREATE PROCEDURE sp_delete_log_shipping_primary
@primary_server_name sysname,
@primary_database_name sysname,
@delete_secondaries BIT = 0
AS BEGIN
DECLARE @primary_id INT
SET NOCOUNT ON
SELECT @primary_id = primary_id
FROM msdb.dbo.log_shipping_primaries
WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name
IF (@primary_id IS NULL)
RETURN (0)
BEGIN TRANSACTION
IF (EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondaries WHERE primary_id = @primary_id))
BEGIN
IF (@delete_secondaries = 0)
BEGIN
RAISERROR (14429,-1,-1)
goto rollback_quit
END
DELETE FROM msdb.dbo.log_shipping_secondaries WHERE primary_id = @primary_id
IF (@@ERROR <> 0)
GOTO rollback_quit
END
DELETE FROM msdb.dbo.log_shipping_primaries WHERE primary_id = @primary_id
IF (@@ERROR <> 0)
GOTO rollback_quit
COMMIT TRANSACTION
DECLARE @i INT
SELECT @i = COUNT(*) FROM msdb.dbo.log_shipping_primaries
IF (@i=0)
EXECUTE msdb.dbo.sp_delete_log_shipping_monitor_jobs
RETURN (0)
rollback_quit:
ROLLBACK TRANSACTION
RETURN(1) -- error
END
go
/**************************************************************/
/* sp_delete_log_shipping_secondary */
/**************************************************************/
PRINT ''
PRINT 'Creating sp_delete_log_shipping_secondary...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_secondary' AND type = N'P') )
drop procedure sp_delete_log_shipping_secondary
go
CREATE PROCEDURE sp_delete_log_shipping_secondary
@secondary_server_name sysname,
@secondary_database_name sysname
AS BEGIN
SET NOCOUNT ON
DELETE FROM msdb.dbo.log_shipping_secondaries WHERE
secondary_server_name = @secondary_server_name AND
secondary_database_name = @secondary_database_name
END
go
/**************************************************************/
/* sp_log_shipping_in_sync */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_log_shipping_in_sync...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_in_sync' AND type = N'P') )
drop procedure sp_log_shipping_in_sync
go
CREATE PROCEDURE sp_log_shipping_in_sync
@last_updated DATETIME,
@compare_with DATETIME,
@threshold INT,
@outage_start_time INT,
@outage_end_time INT,
@outage_weekday_mask INT,
@enabled BIT = 1,
@delta INT = NULL OUTPUT
AS BEGIN
SET NOCOUNT ON
DECLARE @cur_time INT
SELECT @delta = DATEDIFF (mi, @last_updated, @compare_with)
-- in sync
IF (@delta <= @threshold)
RETURN (0) -- in sync
IF (@enabled = 0)
RETURN(0) -- in sync
IF (@outage_weekday_mask & DATEPART(dw, GETDATE ()) > 0) -- potentially in outage window
BEGIN
SELECT @cur_time = DATEPART (hh, GETDATE()) * 10000 +
DATEPART (mi, GETDATE()) * 100 +
DATEPART (ss, GETDATE())
-- outage doesn't span midnight
IF (@outage_start_time < @outage_end_time)
BEGIN
IF (@cur_time >= @outage_start_time AND @cur_time < @outage_end_time)
RETURN(1) -- in outage
END
-- outage does span midnight
ELSE IF (@outage_start_time > @outage_end_time)
BEGIN
IF (@cur_time >= @outage_start_time OR @cur_time < @outage_end_time)
RETURN(1) -- in outage
END
END
RETURN(-1 ) -- not in outage, not in sync
END
go
/**************************************************************/
/* sp_log_shipping_get_date_from_file */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_log_shipping_get_date_from_file...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_get_date_from_file' AND type = N'P') )
drop procedure sp_log_shipping_get_date_from_file
go
CREATE PROCEDURE sp_log_shipping_get_date_from_file
@db_name sysname,
@filename NVARCHAR (500),
@file_date DATETIME OUTPUT
AS
BEGIN
SET NOCOUNT ON
DECLARE @tempname NVARCHAR (500)
IF (LEN (@filename) - (LEN(@db_name) + LEN ('_tlog_')) <= 0)
RETURN(1) -- filename string isn't long enough
SELECT @tempname = RIGHT (@filename, LEN (@filename) - (LEN(@db_name) + LEN ('_tlog_')))
IF (CHARINDEX ('.',@tempname,0) > 0)
SELECT @tempname = LEFT (@tempname, CHARINDEX ('.',@tempname,0) - 1)
IF (LEN (@tempname) <> 8 AND LEN (@tempname) <> 12)
RETURN (1) -- error must be yyyymmddhhmm or yyyymmdd
IF (ISNUMERIC (@tempname) = 0 OR CHARINDEX ('.',@tempname,0) <> 0 OR CONVERT (FLOAT,SUBSTRING (@tempname, 1,8)) < 1 )
RETURN (1) -- must be numeric, can't contain any '.' etc
SELECT @file_date = CONVERT (DATETIME,SUBSTRING (@tempname, 1,8),112)
IF (LEN (@tempname) = 12)
BEGIN
SELECT @file_date = DATEADD (hh, CONVERT (INT, SUBSTRING (@tempname,9,2)),@file_date)
SELECT @file_date = DATEADD (mi, CONVERT (INT, SUBSTRING (@tempname,11,2)),@file_date)
END
RETURN (0) -- success
END
go
/**************************************************************/
/* sp_get_log_shipping_monitor_info */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_get_log_shipping_monitor_info...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_get_log_shipping_monitor_info' AND type = N'P') )
drop procedure sp_get_log_shipping_monitor_info
go
CREATE PROCEDURE sp_get_log_shipping_monitor_info
@primary_server_name sysname = N'%',
@primary_database_name sysname = N'%',
@secondary_server_name sysname = N'%',
@secondary_database_name sysname = N'%'
AS BEGIN
SET NOCOUNT ON
DECLARE @lsp TABLE (
primary_server_name sysname COLLATE database_default NOT NULL,
primary_database_name sysname COLLATE database_default NOT NULL,
secondary_server_name sysname COLLATE database_default NOT NULL,
secondary_database_name sysname COLLATE database_default NOT NULL,
backup_threshold INT NOT NULL,
backup_threshold_alert INT NOT NULL,
backup_threshold_alert_enabled BIT NOT NULL,
last_backup_filename NVARCHAR(500) COLLATE database_default NOT NULL,
last_backup_last_updated DATETIME NOT NULL,
backup_outage_start_time INT NOT NULL,
backup_outage_end_time INT NOT NULL,
backup_outage_weekday_mask INT NOT NULL,
backup_in_sync INT NULL, -- 0 = in sync, -1 = out of sync, 1 = in outage window
backup_delta INT NULL,
last_copied_filename NVARCHAR(500) COLLATE database_default NOT NULL,
last_copied_last_updated DATETIME NOT NULL,
last_loaded_filename NVARCHAR(500) COLLATE database_default NOT NULL,
last_loaded_last_updated DATETIME NOT NULL,
copy_delta INT NULL,
copy_enabled BIT NOT NULL,
load_enabled BIT NOT NULL,
out_of_sync_threshold INT NOT NULL,
load_threshold_alert INT NOT NULL,
load_threshold_alert_enabled BIT NOT NULL,
load_outage_start_time INT NOT NULL,
load_outage_end_time INT NOT NULL,
load_outage_weekday_mask INT NOT NULL,
load_in_sync INT NULL, -- 0 = in sync, -1 = out of sync, 1 = in outage window
load_delta INT NULL,
maintenance_plan_id UNIQUEIDENTIFIER NULL,
secondary_plan_id UNIQUEIDENTIFIER NOT NULL)
INSERT INTO @lsp
SELECT
primary_server_name,
primary_database_name,
secondary_server_name,
secondary_database_name,
backup_threshold,
p.threshold_alert,
p.threshold_alert_enabled,
last_backup_filename,
p.last_updated,
p.planned_outage_start_time,
p.planned_outage_end_time,
p.planned_outage_weekday_mask,
NULL,
NULL,
last_copied_filename,
last_copied_last_updated,
last_loaded_filename,
last_loaded_last_updated,
NULL,
copy_enabled,
load_enabled,
out_of_sync_threshold,
s.threshold_alert,
s.threshold_alert_enabled,
s.planned_outage_start_time,
s.planned_outage_weekday_mask,
s.planned_outage_end_time,
NULL,
NULL,
maintenance_plan_id,
secondary_plan_id
FROM msdb.dbo.log_shipping_primaries p, msdb.dbo.log_shipping_secondaries s
WHERE
p.primary_id = s.primary_id AND
primary_server_name LIKE @primary_server_name AND
primary_database_name LIKE @primary_database_name AND
secondary_server_name LIKE @secondary_server_name AND
secondary_database_name LIKE @secondary_database_name
DECLARE @load_in_sync INT
DECLARE @backup_in_sync INT
DECLARE @_primary_server_name sysname
DECLARE @_primary_database_name sysname
DECLARE @_secondary_server_name sysname
DECLARE @_secondary_database_name sysname
DECLARE @last_loaded_last_updated DATETIME
DECLARE @last_loaded_filename NVARCHAR (500)
DECLARE @last_copied_filename NVARCHAR (500)
DECLARE @last_backup_last_updated DATETIME
DECLARE @last_backup_filename NVARCHAR (500)
DECLARE @backup_outage_start_time INT
DECLARE @backup_outage_end_time INT
DECLARE @backup_outage_weekday_mask INT
DECLARE @backup_threshold INT
DECLARE @backup_threshold_alert_enabled BIT
DECLARE @load_outage_start_time INT
DECLARE @load_outage_end_time INT
DECLARE @load_outage_weekday_mask INT
DECLARE @load_threshold INT
DECLARE @load_threshold_alert_enabled BIT
DECLARE @backupdt DATETIME
DECLARE @restoredt DATETIME
DECLARE @copydt DATETIME
DECLARE @rv INT
DECLARE @dt DATETIME
DECLARE @copy_delta INT
DECLARE @load_delta INT
DECLARE @backup_delta INT
DECLARE @last_copied_last_updated DATETIME
SELECT @dt = GETDATE ()
DECLARE sync_update CURSOR FOR
SELECT
primary_server_name,
primary_database_name,
secondary_server_name,
secondary_database_name,
last_backup_filename,
last_backup_last_updated,
last_loaded_filename,
last_loaded_last_updated,
backup_outage_start_time,
backup_outage_end_time,
backup_outage_weekday_mask,
backup_threshold,
backup_threshold_alert_enabled,
load_outage_start_time,
load_outage_end_time,
out_of_sync_threshold,
load_outage_weekday_mask,
load_threshold_alert_enabled,
last_copied_filename,
last_copied_last_updated
FROM @lsp
FOR READ ONLY
OPEN sync_update
loop:
FETCH NEXT FROM sync_update INTO
@_primary_server_name,
@_primary_database_name,
@_secondary_server_name,
@_secondary_database_name,
@last_backup_filename,
@last_backup_last_updated,
@last_loaded_filename,
@last_loaded_last_updated,
@backup_outage_start_time,
@backup_outage_end_time,
@backup_outage_weekday_mask,
@backup_threshold,
@backup_threshold_alert_enabled,
@load_outage_start_time,
@load_outage_end_time,
@load_threshold,
@load_outage_weekday_mask,
@load_threshold_alert_enabled,
@last_copied_filename,
@last_copied_last_updated
IF @@fetch_status <> 0
GOTO _loop
EXECUTE @rv = sp_log_shipping_get_date_from_file @_primary_database_name, @last_backup_filename, @backupdt OUTPUT
IF (@rv <> 0)
SELECT @backupdt = @last_backup_last_updated
EXECUTE @rv = sp_log_shipping_get_date_from_file @_primary_database_name, @last_loaded_filename, @restoredt OUTPUT
IF (@rv <> 0)
SELECT @restoredt = @last_loaded_last_updated
EXECUTE @rv = sp_log_shipping_get_date_from_file @_primary_database_name, @last_copied_filename, @copydt OUTPUT
IF (@rv <> 0)
SELECT @copydt = @last_copied_last_updated
EXECUTE @load_in_sync = msdb.dbo.sp_log_shipping_in_sync
@restoredt,
@backupdt,
@load_threshold,
@load_outage_start_time,
@load_outage_end_time,
@load_outage_weekday_mask,
@load_threshold_alert_enabled,
@load_delta OUTPUT
EXECUTE @backup_in_sync = msdb.dbo.sp_log_shipping_in_sync
@last_backup_last_updated,
@dt,
@backup_threshold,
@backup_outage_start_time,
@backup_outage_end_time,
@backup_outage_weekday_mask,
@backup_threshold_alert_enabled,
@backup_delta OUTPUT
EXECUTE msdb.dbo.sp_log_shipping_in_sync
@copydt,
@backupdt,
1,0,0,0,0,
@copy_delta OUTPUT
UPDATE @lsp
SET backup_in_sync = @backup_in_sync, load_in_sync = @load_in_sync,
copy_delta = @copy_delta, load_delta = @load_delta, backup_delta = @backup_delta
WHERE primary_server_name = @_primary_server_name AND
secondary_server_name = @_secondary_server_name AND
primary_database_name = @_primary_database_name AND
secondary_database_name = @_secondary_database_name
GOTO loop
_loop:
CLOSE sync_update
DEALLOCATE sync_update
SELECT * FROM @lsp
END
go
/**************************************************************/
/* sp_update_log_shipping_monitor_info */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_update_log_shipping_monitor_info...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_update_log_shipping_monitor_info' AND type = N'P') )
DROP PROCEDURE sp_update_log_shipping_monitor_info
go
CREATE PROCEDURE sp_update_log_shipping_monitor_info
@primary_server_name sysname,
@primary_database_name sysname,
@secondary_server_name sysname,
@secondary_database_name sysname,
@backup_threshold INT = NULL,
@backup_threshold_alert INT = NULL,
@backup_threshold_alert_enabled BIT = NULL,
@backup_outage_start_time INT = NULL,
@backup_outage_end_time INT = NULL,
@backup_outage_weekday_mask INT = NULL,
@copy_enabled BIT = NULL,
@load_enabled BIT = NULL,
@out_of_sync_threshold INT = NULL,
@out_of_sync_threshold_alert INT = NULL,
@out_of_sync_threshold_alert_enabled BIT = NULL,
@out_of_sync_outage_start_time INT = NULL,
@out_of_sync_outage_end_time INT = NULL,
@out_of_sync_outage_weekday_mask INT = NULL
AS BEGIN
SET NOCOUNT ON
DECLARE @_backup_threshold INT
DECLARE @_backup_threshold_alert INT
DECLARE @_backup_threshold_alert_enabled BIT
DECLARE @_backup_outage_start_time INT
DECLARE @_backup_outage_end_time INT
DECLARE @_backup_outage_weekday_mask INT
DECLARE @_copy_enabled BIT
DECLARE @_load_enabled BIT
DECLARE @_out_of_sync_threshold INT
DECLARE @_out_of_sync_threshold_alert INT
DECLARE @_out_of_sync_threshold_alert_enabled BIT
DECLARE @_out_of_sync_outage_start_time INT
DECLARE @_out_of_sync_outage_end_time INT
DECLARE @_out_of_sync_outage_weekday_mask INT
-- check that the primary exists
IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name))
BEGIN
DECLARE @pp sysname
SELECT @pp = @primary_server_name + N'.' + @primary_database_name
RAISERROR (14262, 16, 1, N'primary_server_name.primary_database_name', @pp)
RETURN (1) -- error
END
-- check that the secondary exists
IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondaries WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name))
BEGIN
DECLARE @sp sysname
SELECT @sp = @secondary_server_name + N'.' + @secondary_database_name
RAISERROR (14262, 16, 1, N'secondary_server_name.secondary_database_name', @sp)
RETURN (1) -- error
END
-- load the original variables
SELECT
@_backup_threshold = backup_threshold,
@_backup_threshold_alert = p.threshold_alert,
@_backup_threshold_alert_enabled = p.threshold_alert_enabled,
@_backup_outage_start_time = p.planned_outage_start_time,
@_backup_outage_end_time = p.planned_outage_end_time,
@_backup_outage_weekday_mask = p.planned_outage_weekday_mask,
@_copy_enabled = copy_enabled,
@_load_enabled = load_enabled,
@_out_of_sync_threshold = out_of_sync_threshold,
@_out_of_sync_threshold_alert = s.threshold_alert,
@_out_of_sync_threshold_alert_enabled = s.threshold_alert_enabled,
@_out_of_sync_outage_start_time = s.planned_outage_start_time,
@_out_of_sync_outage_weekday_mask = s.planned_outage_weekday_mask,
@_out_of_sync_outage_end_time = s.planned_outage_end_time
FROM msdb.dbo.log_shipping_primaries p, msdb.dbo.log_shipping_secondaries s
WHERE
p.primary_id = s.primary_id AND
primary_server_name = @primary_server_name AND
primary_database_name = @primary_database_name AND
secondary_server_name = @secondary_server_name AND
secondary_database_name = @secondary_database_name
SELECT @_backup_threshold = ISNULL (@backup_threshold, @_backup_threshold)
SELECT @_backup_threshold_alert = ISNULL (@backup_threshold_alert, @_backup_threshold_alert)
SELECT @_backup_threshold_alert_enabled = ISNULL (@backup_threshold_alert_enabled, @_backup_threshold_alert_enabled)
SELECT @_backup_outage_start_time = ISNULL (@backup_outage_start_time, @_backup_outage_start_time)
SELECT @_backup_outage_end_time = ISNULL (@backup_outage_end_time, @_backup_outage_end_time)
SELECT @_backup_outage_weekday_mask = ISNULL (@backup_outage_weekday_mask, @_backup_outage_weekday_mask)
SELECT @_copy_enabled = ISNULL (@copy_enabled, @_copy_enabled)
SELECT @_load_enabled = ISNULL (@load_enabled, @_load_enabled)
SELECT @_out_of_sync_threshold = ISNULL (@out_of_sync_threshold, @_out_of_sync_threshold)
SELECT @_out_of_sync_threshold_alert = ISNULL (@out_of_sync_threshold_alert, @_out_of_sync_threshold_alert)
SELECT @_out_of_sync_threshold_alert_enabled = ISNULL (@out_of_sync_threshold_alert_enabled, @_out_of_sync_threshold_alert_enabled)
SELECT @_out_of_sync_outage_start_time = ISNULL (@out_of_sync_outage_start_time, @_out_of_sync_outage_start_time)
SELECT @_out_of_sync_outage_end_time = ISNULL (@out_of_sync_outage_end_time, @_out_of_sync_outage_end_time)
SELECT @_out_of_sync_outage_weekday_mask = ISNULL (@out_of_sync_outage_weekday_mask, @_out_of_sync_outage_weekday_mask)
-- updates
UPDATE msdb.dbo.log_shipping_primaries SET
backup_threshold = @_backup_threshold,
threshold_alert = @_backup_threshold_alert,
threshold_alert_enabled = @_backup_threshold_alert_enabled,
planned_outage_start_time = @_backup_outage_start_time,
planned_outage_end_time = @_backup_outage_end_time,
planned_outage_weekday_mask = @_backup_outage_weekday_mask
WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name
UPDATE msdb.dbo.log_shipping_secondaries SET
copy_enabled = @_copy_enabled,
load_enabled = @_load_enabled,
out_of_sync_threshold = @_out_of_sync_threshold,
threshold_alert = @_out_of_sync_threshold_alert,
threshold_alert_enabled = @_out_of_sync_threshold_alert_enabled,
planned_outage_start_time = @_out_of_sync_outage_start_time,
planned_outage_end_time = @_out_of_sync_outage_weekday_mask,
planned_outage_weekday_mask = @_out_of_sync_outage_end_time
WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name
RETURN(0)
END
go
/**************************************************************/
/* sp_delete_log_shipping_monitor_info */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_delete_log_shipping_monitor_info...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_delete_log_shipping_monitor_info' AND type = N'P') )
DROP PROCEDURE sp_delete_log_shipping_monitor_info
go
CREATE PROCEDURE sp_delete_log_shipping_monitor_info
@primary_server_name sysname,
@primary_database_name sysname,
@secondary_server_name sysname,
@secondary_database_name sysname
AS BEGIN
-- check that the primary exists
IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name))
BEGIN
DECLARE @pp sysname
SELECT @pp = @primary_server_name + N'.' + @primary_database_name
RAISERROR (14262, 16, 1, N'primary_server_name.primary_database_name', @pp)
RETURN (1) -- error
END
-- check that the secondary exists
IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondaries WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name))
BEGIN
DECLARE @sp sysname
SELECT @sp = @secondary_server_name + N'.' + @secondary_database_name
RAISERROR (14262, 16, 1, N'secondary_server_name.secondary_database_name', @sp)
RETURN (1) -- error
END
BEGIN TRANSACTION
-- delete the secondary
DELETE FROM msdb.dbo.log_shipping_secondaries WHERE secondary_server_name = @secondary_server_name AND secondary_database_name = @secondary_database_name
IF (@@error <> 0)
goto rollback_quit
-- if there are no more secondaries for this primary then delete it
IF (NOT EXISTS (SELECT * FROM msdb.dbo.log_shipping_primaries p, msdb.dbo.log_shipping_secondaries s WHERE p.primary_id = s.primary_id AND primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name))
BEGIN
DELETE FROM msdb.dbo.log_shipping_primaries WHERE primary_server_name = @primary_server_name AND primary_database_name = @primary_database_name
IF (@@error <> 0)
goto rollback_quit
END
COMMIT TRANSACTION
RETURN (0)
rollback_quit:
ROLLBACK TRANSACTION
RETURN(1) -- Failure
END
go
/**************************************************************/
/* sp_remove_log_shipping_monitor_account */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_remove_log_shipping_monitor_account...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_remove_log_shipping_monitor_account' AND type = N'P') )
DROP PROCEDURE sp_remove_log_shipping_monitor_account
go
CREATE PROCEDURE sp_remove_log_shipping_monitor_account
AS
BEGIN
SET NOCOUNT ON
EXECUTE sp_dropuser N'log_shipping_monitor_probe'
EXECUTE sp_droplogin N'log_shipping_monitor_probe'
END
go
/**************************************************************/
/* sp_log_shipping_monitor_backup */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_log_shipping_monitor_backup...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_monitor_backup' AND type = N'P') )
drop procedure sp_log_shipping_monitor_backup
go
CREATE PROCEDURE sp_log_shipping_monitor_backup AS
BEGIN
DECLARE @primary_id sysname
DECLARE @primary_server_name sysname
DECLARE @primary_database_name sysname
DECLARE @maintenance_plan_id UNIQUEIDENTIFIER
DECLARE @backup_threshold INT
DECLARE @threshold_alert INT
DECLARE @threshold_alert_enabled BIT
DECLARE @last_backup_filename sysname
DECLARE @last_updated DATETIME
DECLARE @planned_outage_start_time INT
DECLARE @planned_outage_end_time INT
DECLARE @planned_outage_weekday_mask INT
DECLARE @sync_status INT
DECLARE @backup_delta INT
DECLARE @delta_string NVARCHAR (10)
DECLARE @dt DATETIME
SELECT @dt = GETDATE ()
SET NOCOUNT ON
DECLARE bmlsp_cur CURSOR FOR
SELECT primary_id,
primary_server_name,
primary_database_name,
maintenance_plan_id,
backup_threshold,
threshold_alert,
threshold_alert_enabled,
last_backup_filename,
last_updated,
planned_outage_start_time,
planned_outage_end_time,
planned_outage_weekday_mask
FROM msdb.dbo.log_shipping_primaries
FOR READ ONLY
OPEN bmlsp_cur
loop:
FETCH NEXT FROM bmlsp_cur
INTO @primary_id,
@primary_server_name,
@primary_database_name,
@maintenance_plan_id,
@backup_threshold,
@threshold_alert,
@threshold_alert_enabled,
@last_backup_filename,
@last_updated,
@planned_outage_start_time,
@planned_outage_end_time,
@planned_outage_weekday_mask
IF @@FETCH_STATUS <> 0 -- nothing more to fetch, finish the loop
GOTO _loop
EXECUTE @sync_status = sp_log_shipping_in_sync
@last_updated,
@dt,
@backup_threshold,
@planned_outage_start_time,
@planned_outage_end_time,
@planned_outage_weekday_mask,
@threshold_alert_enabled,
@backup_delta OUTPUT
IF (@sync_status < 0)
BEGIN
SELECT @delta_string = CONVERT (NVARCHAR(10), @backup_delta)
RAISERROR (@threshold_alert, 16, 1, @primary_server_name, @primary_database_name, @delta_string)
END
GOTO loop
_loop:
CLOSE bmlsp_cur
DEALLOCATE bmlsp_cur
END
go
/**************************************************************/
/* sp_log_shipping_monitor_restore */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_log_shipping_monitor_restore...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_log_shipping_monitor_restore' AND type = N'P') )
drop procedure sp_log_shipping_monitor_restore
go
CREATE PROCEDURE sp_log_shipping_monitor_restore AS
BEGIN
SET NOCOUNT ON
DECLARE @primary_id INT
DECLARE @secondary_server_name sysname
DECLARE @secondary_database_name sysname
DECLARE @secondary_plan_id UNIQUEIDENTIFIER
DECLARE @out_of_sync_threshold INT
DECLARE @threshold_alert INT
DECLARE @threshold_alert_enabled BIT
DECLARE @last_loaded_filename NVARCHAR (500)
DECLARE @last_backup_filename NVARCHAR (500)
DECLARE @primary_database_name sysname
DECLARE @last_loaded_last_updated DATETIME
DECLARE @last_backup_last_updated DATETIME
DECLARE @planned_outage_start_time INT
DECLARE @planned_outage_end_time INT
DECLARE @planned_outage_weekday_mask INT
DECLARE @sync_status INT
DECLARE @sync_delta INT
DECLARE @delta_string NVARCHAR(10)
SET NOCOUNT ON
DECLARE @backupdt DATETIME
DECLARE @restoredt DATETIME
DECLARE @rv INT
DECLARE rmlsp_cur CURSOR FOR
SELECT s.primary_id,
s.secondary_server_name,
s.secondary_database_name,
s.secondary_plan_id,
s.out_of_sync_threshold,
s.threshold_alert,
s.threshold_alert_enabled,
s.last_loaded_filename,
s.last_loaded_last_updated,
p.last_backup_filename,
p.last_updated,
p.primary_database_name,
s.planned_outage_start_time,
s.planned_outage_end_time,
s.planned_outage_weekday_mask
FROM msdb.dbo.log_shipping_secondaries s
INNER JOIN msdb.dbo.log_shipping_primaries p
ON s.primary_id = p.primary_id
FOR READ ONLY
OPEN rmlsp_cur
loop:
FETCH NEXT FROM rmlsp_cur
INTO @primary_id,
@secondary_server_name,
@secondary_database_name,
@secondary_plan_id,
@out_of_sync_threshold,
@threshold_alert,
@threshold_alert_enabled,
@last_loaded_filename,
@last_loaded_last_updated,
@last_backup_filename,
@last_backup_last_updated,
@primary_database_name,
@planned_outage_start_time,
@planned_outage_end_time,
@planned_outage_weekday_mask
IF @@FETCH_STATUS <> 0 -- nothing more to fetch, finish the loop
GOTO _loop
EXECUTE @rv = sp_log_shipping_get_date_from_file @primary_database_name, @last_backup_filename, @backupdt OUTPUT
IF (@rv <> 0)
SELECT @backupdt = @last_backup_last_updated
EXECUTE @rv = sp_log_shipping_get_date_from_file @primary_database_name, @last_loaded_filename, @restoredt OUTPUT
IF (@rv <> 0)
SELECT @restoredt = @last_loaded_last_updated
EXECUTE @sync_status = sp_log_shipping_in_sync
@restoredt,
@backupdt,
@out_of_sync_threshold,
@planned_outage_start_time,
@planned_outage_end_time,
@planned_outage_weekday_mask,
@threshold_alert_enabled,
@sync_delta OUTPUT
IF (@sync_status < 0)
BEGIN
SELECT @delta_string = CONVERT (NVARCHAR(10), @sync_delta)
RAISERROR (@threshold_alert, 16, 1, @secondary_server_name, @secondary_database_name, @delta_string)
END
GOTO loop
_loop:
CLOSE rmlsp_cur
DEALLOCATE rmlsp_cur
END
go
/**************************************************************/
/* sp_change_monitor_role */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_change_monitor_role...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_change_monitor_role' AND type = N'P') )
DROP PROCEDURE sp_change_monitor_role
go
CREATE PROCEDURE sp_change_monitor_role
@primary_server sysname,
@secondary_server sysname,
@database sysname,
@new_source NVARCHAR (128)
AS BEGIN
SET NOCOUNT ON
BEGIN TRANSACTION
-- drop the secondary
DELETE FROM msdb.dbo.log_shipping_secondaries
WHERE secondary_server_name = @secondary_server AND secondary_database_name = @database
IF (@@ROWCOUNT <> 1)
BEGIN
ROLLBACK TRANSACTION
RAISERROR (14442,-1,-1)
return(1)
END
-- let everyone know that we are the new primary
UPDATE msdb.dbo.log_shipping_primaries
SET primary_server_name = @secondary_server, primary_database_name = @database, source_directory = @new_source
WHERE primary_server_name = @primary_server AND primary_database_name = @database
IF (@@ROWCOUNT <> 1)
BEGIN
ROLLBACK TRANSACTION
RAISERROR (14442,-1,-1)
return(1)
END
COMMIT TRANSACTION
END
go
/**************************************************************/
/* sp_create_log_shipping_monitor_account */
/**************************************************************/
PRINT ''
PRINT 'Creating procedure sp_create_log_shipping_monitor_account...'
go
IF (EXISTS (SELECT * from msdb.dbo.sysobjects WHERE name = N'sp_create_log_shipping_monitor_account' AND type = N'P') )
drop procedure sp_create_log_shipping_monitor_account
go
CREATE PROCEDURE sp_create_log_shipping_monitor_account @password sysname
AS
BEGIN
DECLARE @rv INT
SET NOCOUNT ON
-- raise an error if the password already exists
if exists(select * from master.dbo.syslogins where loginname = N'log_shipping_monitor_probe')
begin
raiserror(15025,-1,-1,N'log_shipping_monitor_probe')
RETURN (1) -- error
end
IF (@password = N'')
BEGIN
EXECUTE @rv = sp_addlogin N'log_shipping_monitor_probe', @defdb = N'msdb'
IF @@error <>0 or @rv <> 0
RETURN (1) -- error
END
ELSE
BEGIN
EXECUTE @rv = sp_addlogin N'log_shipping_monitor_probe', @password, N'msdb'
IF @@error <>0 or @rv <> 0
RETURN (1) -- error
END
EXECUTE @rv = sp_grantdbaccess N'log_shipping_monitor_probe', N'log_shipping_monitor_probe'
IF @@error <>0 or @rv <> 0
RETURN (1) -- error
GRANT UPDATE ON log_shipping_primaries TO log_shipping_monitor_probe
GRANT UPDATE ON log_shipping_secondaries TO log_shipping_monitor_probe
GRANT SELECT ON log_shipping_primaries TO log_shipping_monitor_probe
GRANT SELECT ON log_shipping_secondaries TO log_shipping_monitor_probe
RETURN (0)
END
go
/**************************************************************/
/* INTEGRATION SERVICES SECTION */
/**************************************************************/
USE msdb
GO
/***************************************************************/
/* Create SSIS roles */
/***************************************************************/
if not exists (select * from dbo.sysusers where [name] = N'db_ssisadmin' and [issqlrole] = 1)
BEGIN
EXEC sp_addrole N'db_ssisadmin'
END
GO
if not exists (select * from dbo.sysusers where [name] = N'db_ssisltduser' and [issqlrole] = 1)
BEGIN
EXEC sp_addrole N'db_ssisltduser'
END
GO
if not exists (select * from dbo.sysusers where [name] = N'db_ssisoperator' and [issqlrole] = 1)
BEGIN
EXEC sp_addrole N'db_ssisoperator'
END
GO
if not exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sysssispackages]'))
BEGIN
CREATE TABLE [dbo].[sysssispackages] (
[name] [sysname] NOT NULL ,
[id] [uniqueidentifier] NOT NULL ,
[description] [nvarchar] (1024) NULL ,
[createdate] [datetime] NOT NULL ,
[folderid] [uniqueidentifier] NOT NULL ,
[ownersid] [varbinary] (85) NOT NULL ,
[packagedata] [image] NOT NULL ,
[packageformat] [int] NOT NULL,
[packagetype] [int] NOT NULL CONSTRAINT [DF__sysssispackages] DEFAULT (0),
[vermajor] [int] NOT NULL,
[verminor] [int] NOT NULL,
[verbuild] [int] NOT NULL,
[vercomments] [nvarchar] (1024) NULL,
[verid] [uniqueidentifier] NOT NULL,
[isencrypted] [bit] NOT NULL CONSTRAINT [DF__sysssispackages_2] DEFAULT (0),
[readrolesid] [varbinary] (85) NULL,
[writerolesid] [varbinary] (85) NULL,
CONSTRAINT [pk_sysssispackages] PRIMARY KEY NONCLUSTERED
(
[folderid],
[name]
) ON [PRIMARY] ,
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
END
else
BEGIN
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='isencrypted' and id =
(select id from msdb.dbo.sysobjects where name='sysssispackages'))
BEGIN
ALTER TABLE [dbo].[sysssispackages] ADD [isencrypted] [bit] NOT NULL CONSTRAINT [DF__sysssispackages_2] DEFAULT (0)
ALTER TABLE [dbo].[sysssispackages] ADD [readrolesid] [varbinary] (85) NULL
ALTER TABLE [dbo].[sysssispackages] ADD [writerolesid] [varbinary] (85) NULL
END
ELSE
BEGIN
IF NOT EXISTS (
select * from msdb.dbo.syscolumns where name='readrolesid' and id =
(select id from msdb.dbo.sysobjects where name='sysssispackages'))
BEGIN
ALTER TABLE [dbo].[sysssispackages] DROP COLUMN [readrole]
ALTER TABLE [dbo].[sysssispackages] DROP COLUMN [writerole]
ALTER TABLE [dbo].[sysssispackages] ADD [readrolesid] [varbinary] (85) NULL
ALTER TABLE [dbo].[sysssispackages] ADD [writerolesid] [varbinary] (85) NULL
END
END
END
GO
/**************************************************************/
/* sysmaintplan_plans */
/**************************************************************/
PRINT ''
PRINT 'Creating view sysmaintplan_plans...'
go
IF (NOT OBJECT_ID(N'dbo.sysmaintplan_plans', 'V') IS NULL)
DROP VIEW sysmaintplan_plans
go
CREATE VIEW sysmaintplan_plans
AS
SELECT
s.name AS [name],
s.id AS [id],
s.description AS [description],
s.createdate AS [create_date],
suser_sname(s.ownersid) AS [owner],
s.vermajor AS [version_major],
s.verminor AS [version_minor],
s.verbuild AS [version_build],
s.vercomments AS [version_comments],
ISNULL((select TOP 1 msx_plan from sysmaintplan_subplans where plan_id = s.id), 0) AS [from_msx],
CASE WHEN (NOT EXISTS (select TOP 1 msx_job_id
from sysmaintplan_subplans subplans, sysjobservers jobservers
where plan_id = s.id
and msx_job_id is not null
and subplans.msx_job_id = jobservers.job_id
and server_id != 0))
then 0
else 1 END AS [has_targets]
FROM
msdb.dbo.sysssispackages AS s
WHERE
(s.folderid = '08aa12d5-8f98-4dab-a4fc-980b150a5dc8' and s.packagetype = 6)
go
if not exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sysssispackagefolders]'))
BEGIN
CREATE TABLE [dbo].[sysssispackagefolders] (
[folderid] [uniqueidentifier] NOT NULL ,
[parentfolderid] [uniqueidentifier] NULL ,
[foldername] [sysname] NOT NULL ,
CONSTRAINT [PK_sysssispackagefolders] PRIMARY KEY NONCLUSTERED
(
[folderid]
) ON [PRIMARY],
CONSTRAINT [U_sysssispackagefoldersuniquepath] UNIQUE NONCLUSTERED
(
[parentfolderid],
[foldername]
) ON [PRIMARY]
) ON [PRIMARY]
END
GO
-- WARNING! IMPORTANT! If you change sysssislog table schema,
-- be sure to update \dts\src\dtr\runtime\logproviders.cpp !!!
if not exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sysssislog]'))
BEGIN
CREATE TABLE [dbo].[sysssislog] (
[id] [int] NOT NULL IDENTITY PRIMARY KEY,
[event] [sysname] NOT NULL,
[computer] [nvarchar] (128) NOT NULL,
[operator] [nvarchar] (128) NOT NULL,
[source] [nvarchar] (1024) NOT NULL,
[sourceid] [uniqueidentifier] NOT NULL,
[executionid] [uniqueidentifier] NOT NULL,
[starttime] [datetime] NOT NULL,
[endtime] [datetime] NOT NULL,
[datacode] [int] NOT NULL,
[databytes] [image] NULL,
[message] [nvarchar] (2048) NOT NULL,
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
END
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_addlogentry]'))
drop procedure [dbo].[sp_ssis_addlogentry]
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_addlogentry]
@event sysname,
@computer nvarchar(128),
@operator nvarchar(128),
@source nvarchar(1024),
@sourceid uniqueidentifier,
@executionid uniqueidentifier,
@starttime datetime,
@endtime datetime,
@datacode int,
@databytes image,
@message nvarchar(2048)
AS
INSERT INTO sysssislog (
event,
computer,
operator,
source,
sourceid,
executionid,
starttime,
endtime,
datacode,
databytes,
message )
VALUES (
@event,
@computer,
@operator,
@source,
@sourceid,
@executionid,
@starttime,
@endtime,
@datacode,
@databytes,
@message )
RETURN 0
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_listpackages]'))
drop procedure [dbo].[sp_ssis_listpackages]
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_listpackages]
@folderid uniqueidentifier
AS
SELECT
name,
id,
description,
createdate,
folderid,
datalength(packagedata),
vermajor,
verminor,
verbuild,
vercomments,
verid
FROM
sysssispackages
WHERE
[folderid] = @folderid
ORDER BY
name
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_listfolders]'))
drop procedure [dbo].[sp_ssis_listfolders]
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_listfolders]
@parentfolderid uniqueidentifier = NULL
AS
SELECT
folderid,
parentfolderid,
foldername
FROM
sysssispackagefolders
WHERE
[parentfolderid] = @parentfolderid OR
(@parentfolderid IS NULL AND [parentfolderid] IS NULL)
ORDER BY
foldername
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_deletepackage]'))
drop procedure [dbo].[sp_ssis_deletepackage]
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_deletepackage]
@name sysname,
@folderid uniqueidentifier
AS
DECLARE @sid varbinary(85)
DECLARE @writerolesid varbinary(85)
DECLARE @writerole nvarchar(128)
SELECT
@sid = [ownersid],
@writerolesid = [writerolesid]
FROM
sysssispackages
WHERE
[name] = @name AND
[folderid] = @folderid
IF @sid IS NOT NULL
BEGIN
--// The row exists, check security
IF @writerolesid IS NOT NULL
BEGIN
SELECT @writerole = [name] FROM sys.database_principals WHERE [type] = ''R'' AND [sid] = @writerolesid
IF @writerole IS NULL SET @writerole = ''db_ssisadmin''
END
IF @writerole IS NULL
BEGIN
IF (IS_MEMBER(''db_ssisadmin'')<>1) AND (IS_SRVROLEMEMBER(''sysadmin'')<>1)
BEGIN
IF (@sid<>SUSER_SID()) OR (IS_MEMBER(''db_ssisltduser'')<>1)
BEGIN
RAISERROR (14307, -1, -1, @name)
RETURN 1 -- Failure
END
END
END
ELSE
BEGIN
-- If writerrole is set for this package,
-- Allow sysadmins and the members of writer role to delete this package
IF (IS_MEMBER(@writerole)<>1) AND (IS_SRVROLEMEMBER(''sysadmin'')<>1)
BEGIN
IF (@sid<>SUSER_SID()) OR (IS_MEMBER(''db_ssisltduser'')<>1)
BEGIN
RAISERROR (14307, -1, -1, @name)
RETURN 1 -- Failure
END
END
END
END
DELETE FROM sysssispackages
WHERE
[name] = @name AND
[folderid] = @folderid
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_deletefolder]'))
drop procedure [dbo].[sp_ssis_deletefolder]
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_deletefolder]
@folderid uniqueidentifier
AS
DECLARE @name sysname
DECLARE @count int
IF @folderid = ''00000000-0000-0000-0000-000000000000''
BEGIN
RAISERROR (14307, -1, -1, ''00000000-0000-0000-0000-000000000000'')
RETURN 1 -- Failure
END
SELECT
@name = [foldername]
FROM
sysssispackagefolders
WHERE
[folderid] = @folderid
IF @name IS NOT NULL
BEGIN
--// The row exists, check security
IF (IS_MEMBER(''db_ssisadmin'')<>1) AND (IS_SRVROLEMEMBER(''sysadmin'')<>1)
BEGIN
IF (IS_MEMBER(''db_ssisltduser'')<>1)
BEGIN
RAISERROR (14307, -1, -1, @name)
RETURN 1 -- Failure
END
END
END
-- Get the number of packages in this folder
SELECT
@count = count(*)
FROM
sysssispackages
WHERE
[folderid] = @folderid
-- Are there any packages in this folder
IF @count > 0
BEGIN
-- Yes, do not delete
RAISERROR (14593, -1, -1, @name)
RETURN 1 -- Failure
END
-- Get the number of folders in this folder
SELECT
@count = count(*)
FROM
sysssispackagefolders
WHERE
[parentfolderid] = @folderid
-- Are there any folders in this folder
IF @count > 0
BEGIN
-- Yes, do not delete
RAISERROR (14593, -1, -1, @name)
RETURN 1 -- Failure
END
DELETE FROM sysssispackagefolders
WHERE
[folderid] = @folderid
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_getpackage]'))
drop procedure [dbo].[sp_ssis_getpackage]
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_getpackage]
@name sysname,
@folderid uniqueidentifier
AS
DECLARE @sid varbinary(85)
DECLARE @isencrypted bit
DECLARE @readrolesid varbinary(85)
DECLARE @readrole nvarchar(128)
--// Check security, if the row exists
SELECT @sid = [ownersid], @readrolesid = [readrolesid] FROM sysssispackages WHERE [name] = @name AND [folderid] = @folderid
IF @sid IS NOT NULL
BEGIN
IF @readrolesid IS NOT NULL
BEGIN
SELECT @readrole = [name] FROM sys.database_principals WHERE [type] = ''R'' AND [sid] = @readrolesid
IF @readrole IS NULL SET @readrole = ''db_ssisadmin''
END
IF @readrole IS NOT NULL
BEGIN
IF (IS_MEMBER(@readrole)<>1) AND (IS_MEMBER(''db_ssisadmin'')<>1) AND (IS_SRVROLEMEMBER(''sysadmin'')<>1)
BEGIN
IF (IS_MEMBER(''db_ssisltduser'')<>1) OR (@sid<>SUSER_SID())
BEGIN
RAISERROR (14307, -1, -1, @name)
RETURN 1 -- Failure
END
END
END
ELSE
BEGIN
IF (IS_MEMBER(''db_ssisadmin'')<>1) AND (IS_SRVROLEMEMBER(''sysadmin'')<>1) AND (IS_MEMBER(''db_ssisoperator'')<>1)
BEGIN
IF (IS_MEMBER(''db_ssisltduser'')<>1) OR (@sid<>SUSER_SID())
BEGIN
RAISERROR (14586, -1, -1, @name)
RETURN 1 -- Failure
END
END
END
END
SELECT
packagedata
FROM
sysssispackages
WHERE
[name] = @name AND
[folderid] = @folderid
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_getfolder]'))
drop procedure [dbo].[sp_ssis_getfolder]
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_getfolder]
@name sysname,
@parentfolderid uniqueidentifier
AS
SELECT
folder.folderid,
folder.foldername,
folder.parentfolderid,
parent.foldername
FROM
sysssispackagefolders folder
LEFT OUTER JOIN
sysssispackagefolders parent
ON
folder.parentfolderid = parent.folderid
WHERE
folder.foldername = @name AND
(folder.parentfolderid = @parentfolderid OR
(@parentfolderid IS NULL AND folder.parentfolderid IS NULL))
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_putpackage]'))
drop procedure [dbo].[sp_ssis_putpackage]
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_putpackage]
@name sysname,
@id uniqueidentifier,
@description nvarchar(1024),
@createdate datetime,
@folderid uniqueidentifier,
@packagedata image,
@packageformat int,
@packagetype int,
@vermajor int,
@verminor int,
@verbuild int,
@vercomments nvarchar(1024),
@verid uniqueidentifier
AS
SET NOCOUNT ON
DECLARE @sid varbinary(85)
DECLARE @writerolesid varbinary(85)
DECLARE @writerole nvarchar(128)
--// Determine if we should INSERT or UPDATE
SELECT @sid = [ownersid], @writerolesid = [writerolesid] FROM sysssispackages WHERE [name] = @name AND [folderid] = @folderid
IF @sid IS NOT NULL
BEGIN
--// The row exists, check security
IF @writerolesid IS NOT NULL
BEGIN
SELECT @writerole = [name] FROM sys.database_principals WHERE [type] = ''R'' AND [sid] = @writerolesid
IF @writerole IS NULL SET @writerole = ''db_ssisadmin''
END
IF @writerole IS NULL
BEGIN
IF (IS_MEMBER(''db_ssisadmin'')<>1) AND (IS_SRVROLEMEMBER(''sysadmin'')<>1)
BEGIN
IF (@sid<>SUSER_SID()) OR (IS_MEMBER(''db_ssisltduser'')<>1)
BEGIN
RAISERROR (14307, -1, -1, @name)
RETURN 1 -- Failure
END
END
END
ELSE
BEGIN
IF (IS_MEMBER(@writerole)<>1) AND (IS_MEMBER(''db_ssisadmin'')<>1) AND (IS_SRVROLEMEMBER(''sysadmin'')<>1)
BEGIN
IF (@sid<>SUSER_SID()) OR (IS_MEMBER(''db_ssisltduser'')<>1)
BEGIN
RAISERROR (14307, -1, -1, @name)
RETURN 1 -- Failure
END
END
END
--// Security check passed, UPDATE now
UPDATE sysssispackages
SET
id = @id,
description = @description,
createdate = @createdate,
packagedata = @packagedata,
packageformat = @packageformat,
packagetype = @packagetype,
vermajor = @vermajor,
verminor = @verminor,
verbuild = @verbuild,
vercomments = @vercomments,
verid = @verid
WHERE
name = @name AND folderid = @folderid
END
ELSE
BEGIN
--// The row does not exist, check security
IF (IS_MEMBER(''db_ssisltduser'')<>1) AND (IS_MEMBER(''db_ssisadmin'')<>1) AND (IS_SRVROLEMEMBER(''sysadmin'')<>1)
BEGIN
RAISERROR (14307, -1, -1, @name)
RETURN 1 -- Failure
END
--// Security check passed, INSERT now
INSERT INTO sysssispackages (
name,
id,
description,
createdate,
folderid,
ownersid,
packagedata,
packageformat,
packagetype,
vermajor,
verminor,
verbuild,
vercomments,
verid )
VALUES (
@name,
@id,
@description,
@createdate,
@folderid,
SUSER_SID(),
@packagedata,
@packageformat,
@packagetype,
@vermajor,
@verminor,
@verbuild,
@vercomments,
@verid )
END
RETURN 0 -- SUCCESS
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_checkexists]'))
drop procedure [dbo].[sp_ssis_checkexists]
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_checkexists]
@name sysname,
@folderid uniqueidentifier
AS
SET NOCOUNT ON
SELECT TOP 1 1 FROM sysssispackages WHERE [name] = @name AND [folderid] = @folderid
RETURN 0 -- SUCCESS
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_addfolder]'))
drop procedure [dbo].[sp_ssis_addfolder]
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_addfolder]
@parentfolderid uniqueidentifier,
@name sysname,
@folderid uniqueidentifier = NULL
AS
--Check security
IF (IS_MEMBER(''db_ssisltduser'')<>1) AND (IS_MEMBER(''db_ssisadmin'')<>1) AND (IS_SRVROLEMEMBER(''sysadmin'')<>1)
BEGIN
RAISERROR (14591, -1, -1, @name)
RETURN 1 -- Failure
END
--// Security check passed, INSERT now
INSERT INTO sysssispackagefolders (folderid, parentfolderid, foldername)
VALUES (ISNULL(@folderid, NEWID()), @parentfolderid, @name)
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_renamefolder]'))
drop procedure [dbo].[sp_ssis_renamefolder]
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_renamefolder]
@folderid uniqueidentifier,
@name sysname
AS
--Check security
IF (IS_MEMBER(''db_ssisltduser'')<>1) AND (IS_MEMBER(''db_ssisadmin'')<>1) AND (IS_SRVROLEMEMBER(''sysadmin'')<>1)
BEGIN
RAISERROR (14591, -1, -1, @name)
RETURN 1 -- Failure
END
--// Security check passed, INSERT now
UPDATE sysssispackagefolders
SET [foldername] = @name
WHERE [folderid] = @folderid
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_setpackageroles]'))
DROP PROCEDURE [dbo].[sp_ssis_setpackageroles]
GO
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_setpackageroles]
@name sysname,
@folderid uniqueidentifier,
@readrole nvarchar (128),
@writerole nvarchar (128)
AS
SET NOCOUNT ON
DECLARE @sid varbinary(85)
--// Determine if we should INSERT or UPDATE
SELECT @sid = ownersid FROM sysssispackages WHERE name = @name AND folderid = @folderid
IF @sid IS NOT NULL
BEGIN
--// The row exists, check security
IF (IS_MEMBER(''db_ssisadmin'')<>1) AND (IS_SRVROLEMEMBER(''sysadmin'')<>1)
BEGIN
IF (@sid<>SUSER_SID())
BEGIN
RAISERROR (14307, -1, -1, @name)
RETURN 1 -- Failure
END
END
--// Security check passed, UPDATE now
DECLARE @readrolesid varbinary(85)
DECLARE @writerolesid varbinary(85)
SELECT @readrolesid = [sid] FROM sys.database_principals WHERE [type] = ''R'' AND [name] = @readrole
SELECT @writerolesid = [sid] FROM sys.database_principals WHERE [type] = ''R'' AND [name] = @writerole
IF @readrolesid IS NULL AND @readrole IS NOT NULL
BEGIN
RAISERROR (15014, -1, -1, @readrole)
RETURN 1
END
IF @writerolesid IS NULL AND @writerole IS NOT NULL
BEGIN
RAISERROR (15014, -1, -1, @writerole)
RETURN 1
END
UPDATE sysssispackages
SET
[readrolesid] = @readrolesid,
[writerolesid] = @writerolesid
WHERE
name = @name AND folderid = @folderid
END
ELSE
BEGIN
RAISERROR (14307, -1, -1, @name)
RETURN 1 -- Failure
END
RETURN 0 -- SUCCESS
'
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_ssis_getpackageroles]'))
DROP PROCEDURE [dbo].[sp_ssis_getpackageroles]
GO
execute sp_executesql
N'CREATE PROCEDURE [dbo].[sp_ssis_getpackageroles]
@name sysname,
@folderid uniqueidentifier
AS
DECLARE @readrolesid varbinary(85)
DECLARE @writerolesid varbinary(85)
DECLARE @readrole nvarchar(128)
DECLARE @writerole nvarchar(128)
SELECT
@readrolesid = [readrolesid],
@writerolesid = [writerolesid]
FROM
sysssispackages
WHERE
[name] = @name AND
[folderid] = @folderid
SELECT @readrole = [name] FROM sys.database_principals WHERE [type] = ''R'' AND [sid] = @readrolesid
SELECT @writerole = [name] FROM sys.database_principals WHERE [type] = ''R'' AND [sid] = @writerolesid
SELECT @readrole AS readrole, @writerole AS writerole
'
GO
GRANT EXECUTE ON [dbo].[sp_ssis_addlogentry] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_addlogentry] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_deletepackage] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_deletepackage] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_deletepackage] TO [db_ssisoperator]
GRANT EXECUTE ON [dbo].[sp_ssis_getpackage] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_getpackage] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_getpackage] TO [db_ssisoperator]
GRANT EXECUTE ON [dbo].[sp_ssis_listpackages] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_listpackages] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_listpackages] TO [db_ssisoperator]
GRANT EXECUTE ON [dbo].[sp_ssis_putpackage] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_putpackage] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_putpackage] TO [db_ssisoperator]
GRANT EXECUTE ON [dbo].[sp_ssis_checkexists] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_checkexists] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_checkexists] TO [db_ssisoperator]
GRANT EXECUTE ON [dbo].[sp_ssis_listfolders] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_listfolders] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_listfolders] TO [db_ssisoperator]
GRANT EXECUTE ON [dbo].[sp_ssis_deletefolder] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_deletefolder] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_addfolder] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_addfolder] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_renamefolder] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_renamefolder] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_getfolder] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_getfolder] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_getfolder] TO [db_ssisoperator]
GRANT EXECUTE ON [dbo].[sp_ssis_setpackageroles] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_setpackageroles] TO [db_ssisltduser]
GRANT EXECUTE ON [dbo].[sp_ssis_getpackageroles] TO [db_ssisadmin]
GRANT EXECUTE ON [dbo].[sp_ssis_getpackageroles] TO [db_ssisltduser]
GO
GRANT ALL ON [dbo].[sysssislog] TO [db_ssisadmin]
GRANT INSERT ON [dbo].[sysssislog] TO [db_ssisltduser]
GRANT SELECT ON [dbo].[sysssislog] TO [db_ssisltduser]
GRANT INSERT ON [dbo].[sysssislog] TO [db_ssisoperator]
GRANT SELECT ON [dbo].[sysssislog] TO [db_ssisoperator]
GO
-- Maintenance Plans
-- Allow SQLAgent on target servers to gather information about
-- maintenance plans from the master.
GRANT EXECUTE ON sp_maintplan_subplans_by_job TO SQLAgentUserRole
GRANT EXECUTE ON sp_maintplan_subplans_by_job TO TargetServersRole
/**************************************************************/
/* */
/* D A T A C O L L E C T O R */
/* */
/**************************************************************/
USE msdb
GO
---------------------------------------------------------------
-- Data Collector: Security: Database Principals
---------------------------------------------------------------
PRINT ''
PRINT 'Create dc_operator role...'
IF ( NOT EXISTS (SELECT * FROM sys.database_principals
WHERE name = N'dc_operator' AND type = 'R'))
BEGIN
CREATE ROLE [dc_operator]
END
ELSE -- if the role exists check to see if it has members
BEGIN
IF NOT EXISTS (SELECT rm.member_principal_id
FROM sys.database_principals dp
INNER JOIN sys.database_role_members rm ON rm.role_principal_id = dp.principal_id
WHERE name = N'dc_operator' AND type = 'R')
BEGIN
-- if the role has no members drop and recreate it
DROP ROLE [dc_operator]
CREATE ROLE [dc_operator]
END
END
GO
EXECUTE sp_addrolemember @rolename = 'db_ssisltduser' ,
@membername = 'dc_operator'
GO
EXECUTE sp_addrolemember @rolename = 'db_ssisoperator' ,
@membername = 'dc_operator'
GO
EXECUTE sp_addrolemember @rolename = 'SQLAgentUserRole' ,
@membername = 'dc_operator'
GO
PRINT ''
PRINT 'Create dc_admin role...'
IF ( NOT EXISTS (SELECT * FROM sys.database_principals
WHERE name = N'dc_admin' AND type = 'R'))
BEGIN
CREATE ROLE [dc_admin]
END
ELSE -- if the role exists check to see if it has members
BEGIN
IF NOT EXISTS (SELECT rm.member_principal_id
FROM sys.database_principals dp
INNER JOIN sys.database_role_members rm ON rm.role_principal_id = dp.principal_id
WHERE name = N'dc_admin' AND type = 'R')
BEGIN
-- if the role has no members drop and recreate it
DROP ROLE [dc_admin]
CREATE ROLE [dc_admin]
END
END
GO
EXECUTE sp_addrolemember @rolename = 'dc_operator' ,
@membername = 'dc_admin'
GO
PRINT ''
PRINT 'Create dc_proxy role...'
IF ( NOT EXISTS (SELECT * FROM sys.database_principals
WHERE name = N'dc_proxy' AND type = 'R'))
BEGIN
CREATE ROLE [dc_proxy]
END
ELSE -- if the role exists check to see if it has members
BEGIN
IF NOT EXISTS (SELECT rm.member_principal_id
FROM sys.database_principals dp
INNER JOIN sys.database_role_members rm ON rm.role_principal_id = dp.principal_id
WHERE name = N'dc_proxy' AND type = 'R')
BEGIN
-- if the role has no members drop and recreate it
DROP ROLE [dc_proxy]
CREATE ROLE [dc_proxy]
END
END
GO
EXECUTE sp_addrolemember @rolename = 'db_ssisltduser' ,
@membername = 'dc_proxy'
GO
EXECUTE sp_addrolemember @rolename = 'db_ssisoperator' ,
@membername = 'dc_proxy'
GO
PRINT ''
PRINT 'Create loginless user that has ownership of data collector agent-related securables...'
IF (NOT EXISTS(SELECT * FROM sys.database_principals WHERE NAME = 'MS_DataCollectorInternalUser'))
BEGIN
CREATE USER [MS_DataCollectorInternalUser] WITHOUT LOGIN
END
GO
EXECUTE sp_addrolemember @rolename = 'db_ssisoperator' ,
@membername = 'MS_DataCollectorInternalUser'
GO
EXECUTE sp_addrolemember @rolename = 'SQLAgentUserRole' ,
@membername = 'MS_DataCollectorInternalUser'
GO
EXECUTE sp_addrolemember @rolename = 'dc_admin' ,
@membername = 'MS_DataCollectorInternalUser'
GO
GRANT IMPERSONATE ON USER::[MS_DataCollectorInternalUser] TO [dc_admin];
GO
---------------------------------------------------------------
-- Configuration store
---------------------------------------------------------------
IF (OBJECT_ID(N'[dbo].[syscollector_config_store_internal]', 'U') IS NULL)
BEGIN
PRINT 'Creating table [dbo].[syscollector_config_store_internal]...'
CREATE TABLE [dbo].[syscollector_config_store_internal] (
parameter_name nvarchar(128) NOT NULL,
parameter_value sql_variant NULL,
CONSTRAINT [PK_syscollector_config_store_internal_paremeter_name] PRIMARY KEY CLUSTERED (parameter_name ASC)
)
END
GO
IF (NOT OBJECT_ID(N'[dbo].[syscollector_config_store]', 'V') IS NULL)
BEGIN
PRINT 'Dropping view [dbo].[syscollector_config_store]...'
DROP VIEW [dbo].[syscollector_config_store]
END
GO
PRINT 'Creating view [dbo].[syscollector_config_store]...'
GO
CREATE VIEW [dbo].[syscollector_config_store]
AS
SELECT
s.parameter_name,
s.parameter_value
FROM
[dbo].[syscollector_config_store_internal] s
GO
-- populate config store with known name and value pairs
IF (NOT EXISTS(SELECT * FROM [dbo].[syscollector_config_store_internal]
WHERE parameter_name = N'MDWInstance'))
BEGIN
INSERT INTO [dbo].[syscollector_config_store_internal] (
parameter_name,
parameter_value
)
VALUES
(
N'MDWInstance',
NULL
)
END
IF (NOT EXISTS(SELECT * FROM [dbo].[syscollector_config_store_internal]
WHERE parameter_name = N'MDWDatabase'))
BEGIN
INSERT INTO [dbo].[syscollector_config_store_internal] (
parameter_name,
parameter_value
)
VALUES
(
N'MDWDatabase',
NULL
)
END
IF (NOT EXISTS(SELECT * FROM [dbo].[syscollector_config_store_internal]
WHERE parameter_name = 'CollectorEnabled'))
BEGIN
INSERT INTO [dbo].[syscollector_config_store_internal] (
parameter_name,
parameter_value
)
VALUES
(
'CollectorEnabled',
0
)
END
IF (NOT EXISTS(SELECT * FROM [dbo].[syscollector_config_store_internal]
WHERE parameter_name = 'CacheWindow'))
BEGIN
INSERT INTO [dbo].[syscollector_config_store_internal] (
parameter_name,
parameter_value
)
VALUES
(
'CacheWindow',
1 --By default, the collector will keep 1 window's worth of uploads
)
END
IF (NOT EXISTS(SELECT * FROM [dbo].[syscollector_config_store_internal]
WHERE parameter_name = 'CacheDirectory'))
BEGIN
INSERT INTO [dbo].[syscollector_config_store_internal] (
parameter_name,
parameter_value
)
VALUES
(
'CacheDirectory',
NULL
)
END
GO
---------------------------------------------------------------
-- Access collector level properties
---------------------------------------------------------------
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_verify_collector_state]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_verify_collector_state]...'
DROP PROCEDURE [dbo].[sp_syscollector_verify_collector_state]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_verify_collector_state]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_verify_collector_state]
@desired_state int
WITH EXECUTE AS OWNER -- 'MS_DataCollectorInternalUser'
AS
BEGIN
DECLARE @collector_enabled INT
SET @collector_enabled = CONVERT(int, (SELECT parameter_value FROM dbo.syscollector_config_store_internal
WHERE parameter_name = 'CollectorEnabled'))
IF (@collector_enabled IS NULL)
BEGIN
RAISERROR(14691, -1, -1)
RETURN(1)
END
IF (@collector_enabled = 0) AND (@desired_state = 1)
BEGIN
RAISERROR(14681, -1, -1)
RETURN(1)
END
IF (@collector_enabled = 1) AND (@desired_state = 0)
BEGIN
RAISERROR(14690, -1, -1)
RETURN(1)
END
RETURN(0)
END
GO
IF (NOT OBJECT_ID('dbo.sp_syscollector_set_warehouse_instance_name', 'P') IS NULL)
BEGIN
DROP PROCEDURE [dbo].[sp_syscollector_set_warehouse_instance_name]
END
GO
PRINT ''
PRINT 'Creating procedure [dbo].[sp_syscollector_set_warehouse_instance_name]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_set_warehouse_instance_name]
@instance_name sysname = NULL
AS
BEGIN
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN(1) -- Failure
END
-- Check if the collector is disabled
DECLARE @retVal int
EXEC @retVal = [dbo].[sp_syscollector_verify_collector_state] @desired_state = 0
IF (@retVal <> 0)
RETURN (1)
UPDATE [msdb].[dbo].[syscollector_config_store_internal]
SET parameter_value = @instance_name
WHERE parameter_name = N'MDWInstance'
RETURN (0)
END
GO
IF (NOT OBJECT_ID('dbo.sp_syscollector_set_warehouse_database_name', 'P') IS NULL)
BEGIN
DROP PROCEDURE [dbo].[sp_syscollector_set_warehouse_database_name]
END
GO
PRINT ''
PRINT 'Creating procedure [dbo].[sp_syscollector_set_warehouse_database_name]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_set_warehouse_database_name]
@database_name sysname = NULL
AS
BEGIN
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN(1) -- Failure
END
-- Check if the collector is disabled
DECLARE @retVal int
EXEC @retVal = [dbo].[sp_syscollector_verify_collector_state] @desired_state = 0
IF (@retVal <> 0)
RETURN (1)
UPDATE [msdb].[dbo].[syscollector_config_store_internal]
SET parameter_value = @database_name
WHERE parameter_name = N'MDWDatabase'
RETURN (0)
END
GO
IF (NOT OBJECT_ID('dbo.sp_syscollector_set_cache_directory', 'P') IS NULL)
BEGIN
DROP PROCEDURE [dbo].[sp_syscollector_set_cache_directory]
END
GO
PRINT ''
PRINT 'Creating procedure [dbo].[sp_syscollector_set_cache_directory]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_set_cache_directory]
@cache_directory nvarchar(255) = NULL
AS
BEGIN
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN(1) -- Failure
END
SET @cache_directory = NULLIF(LTRIM(RTRIM(@cache_directory)), N'')
-- Check if the collector is disabled
DECLARE @retVal int
EXEC @retVal = [dbo].[sp_syscollector_verify_collector_state] @desired_state = 0
IF (@retVal <> 0)
RETURN (1)
UPDATE [msdb].[dbo].[syscollector_config_store_internal]
SET parameter_value = @cache_directory
WHERE parameter_name = N'CacheDirectory'
RETURN (0)
END
GO
IF (NOT OBJECT_ID('dbo.sp_syscollector_set_cache_window', 'P') IS NULL)
BEGIN
DROP PROCEDURE [dbo].[sp_syscollector_set_cache_window]
END
GO
PRINT ''
PRINT 'Creating procedure [dbo].[sp_syscollector_set_cache_window]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_set_cache_window]
@cache_window int = 1
AS
BEGIN
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN(1) -- Failure
END
-- Check if the collector is disabled
DECLARE @retVal int
EXEC @retVal = [dbo].[sp_syscollector_verify_collector_state] @desired_state = 0
IF (@retVal <> 0)
RETURN (1)
IF (@cache_window < -1)
BEGIN
RAISERROR(14687, -1, -1, @cache_window)
RETURN(1)
END
UPDATE [msdb].[dbo].[syscollector_config_store_internal]
SET parameter_value = @cache_window
WHERE parameter_name = N'CacheWindow'
RETURN (0)
END
GO
IF (NOT OBJECT_ID('dbo.sp_syscollector_get_warehouse_connection_string', 'P') IS NULL)
BEGIN
DROP PROCEDURE [dbo].[sp_syscollector_get_warehouse_connection_string]
END
GO
PRINT ''
PRINT 'Creating procedure [dbo].[sp_syscollector_get_warehouse_connection_string]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_get_warehouse_connection_string]
@connection_string nvarchar(512) = NULL OUTPUT
AS
BEGIN
DECLARE @instance_name sysname
DECLARE @database_name sysname
DECLARE @user_name sysname
DECLARE @password sysname
DECLARE @product_version nvarchar(128) -- SERVERPROPERTY('ProductVersion') returns value of type nvarchar(128)
DECLARE @provider_name nvarchar(128)
SELECT @instance_name = CONVERT(sysname,parameter_value)
FROM [msdb].[dbo].[syscollector_config_store_internal]
WHERE parameter_name = N'MDWInstance'
IF (@instance_name IS NULL)
BEGIN
RAISERROR(14686, -1, -1)
RETURN (1)
END
-- '"' is the delimiter for the sql client connection string
SET @instance_name = QUOTENAME(@instance_name, '"')
SELECT @database_name = CONVERT(sysname,parameter_value)
FROM [msdb].[dbo].[syscollector_config_store_internal]
WHERE parameter_name = N'MDWDatabase'
IF (@database_name IS NULL)
BEGIN
RAISERROR(14686, -1, -1)
RETURN (1)
END
SET @database_name = QUOTENAME(@database_name, '"')
SET @product_version = CONVERT(nvarchar(128), SERVERPROPERTY('ProductVersion'))
-- Get Product Major version from string format 'major.minor.build'
SET @provider_name = 'SQLNCLI' + SUBSTRING(@product_version, 0, CHARINDEX('.', @product_version))
SET @connection_string = N'Data Source=' + @instance_name + N';Application Name="Data Collector - MDW";Initial Catalog=' + @database_name
SET @connection_string = @connection_string + N';Use Encryption for Data=true;Trust Server Certificate=true;Provider=' + @provider_name
SET @connection_string = @connection_string + N';Integrated Security=SSPI;Connect Timeout=60;';
RETURN (0)
END
GO
--
-- Return the highest version of the Management Data Warehouse that this
-- Collector is no compatible with. Anything higher than this version
-- is fine.
--
-- If you change this number, make sure to change the corresponding versions
-- in HighestIncompatibleMDWVersion.cs
--
IF (NOT OBJECT_ID('dbo.fn_syscollector_highest_incompatible_mdw_version', 'FN') IS NULL)
BEGIN
DROP FUNCTION [dbo].[fn_syscollector_highest_incompatible_mdw_version]
END
GO
PRINT ''
PRINT 'Creating function [dbo].[fn_syscollector_highest_incompatible_mdw_version]...'
GO
CREATE FUNCTION [dbo].[fn_syscollector_highest_incompatible_mdw_version]()
RETURNS nvarchar(50)
BEGIN
RETURN '10.00.1300.13' -- CTP6
END
GO
---------------------------------------------------------------
-- Collection set
---------------------------------------------------------------
IF (OBJECT_ID(N'[dbo].[syscollector_collection_sets_internal]', 'U') IS NULL)
BEGIN
PRINT 'Creating table [dbo].[syscollector_collection_sets_internal]...'
CREATE TABLE [dbo].[syscollector_collection_sets_internal] (
collection_set_id int IDENTITY NOT NULL,
collection_set_uid uniqueidentifier NOT NULL,
schedule_uid uniqueidentifier NULL, -- schedule to run collection or upload
name sysname NOT NULL, -- name of the collection set, must be unique
name_id int NULL, -- sysmessage id of the name of the set (for localizing system collection set)
target nvarchar(max) NULL, -- future use
is_running bit default 0 NOT NULL, -- is the collection set active
proxy_id int NULL, -- proxy to use to run the collection set
is_system bit NOT NULL, -- indicates MS-shipped collection set
collection_job_id uniqueidentifier NULL, -- id of the collection job
upload_job_id uniqueidentifier NULL, -- id of the upload job
collection_mode smallint default 0 NOT NULL, -- 0 - cached, 1 - non-cached
logging_level smallint default 2 NOT NULL, -- 0 - errors only, 1 - errors & warnings, 2 - detailed
description nvarchar(4000) NULL, -- description of the set
description_id int NULL, -- sysmessage id of the description of the set (for localizing system collection set)
days_until_expiration smallint NOT NULL, -- how long to keep the data from this collection set
dump_on_any_error bit default 0 NOT NULL, -- configure SQL dumper to dump on any SSIS errors
dump_on_codes nvarchar(max) NULL, -- configure SQL dumper to dump when we hit one of the specified SSIS errors
CONSTRAINT [PK_syscollector_collection_sets_internal] PRIMARY KEY CLUSTERED (collection_set_id ASC),
CONSTRAINT [UQ_syscollector_collection_sets_internal_name] UNIQUE (name)
)
ALTER TABLE syscollector_collection_sets_internal
ADD CONSTRAINT [FK_syscollector_collection_sets_internal_sysproxies] FOREIGN KEY(proxy_id)
REFERENCES sysproxies (proxy_id)
ALTER TABLE syscollector_collection_sets_internal
ADD CONSTRAINT [FK_syscollector_collection_sets_collection_sysjobs] FOREIGN KEY(collection_job_id)
REFERENCES sysjobs (job_id)
ALTER TABLE syscollector_collection_sets_internal
ADD CONSTRAINT [FK_syscollector_collection_sets_upload_sysjobs] FOREIGN KEY(upload_job_id)
REFERENCES sysjobs(job_id)
END ELSE BEGIN
IF (NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name = N'name_id' AND id = OBJECT_ID(N'[dbo].[syscollector_collection_sets_internal]')))
BEGIN
PRINT 'Altering table [dbo].[syscollector_collection_sets_internal]...'
ALTER TABLE [dbo].[syscollector_collection_sets_internal] ADD name_id int NULL
END
IF (NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name = N'description_id' AND id = OBJECT_ID(N'[dbo].[syscollector_collection_sets_internal]')))
BEGIN
PRINT 'Altering table [dbo].[syscollector_collection_sets_internal]...'
ALTER TABLE [dbo].[syscollector_collection_sets_internal] ADD description_id int NULL
END
IF (NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name = N'dump_on_any_error' AND id = OBJECT_ID(N'[dbo].[syscollector_collection_sets_internal]')))
BEGIN
PRINT 'Altering table [dbo].[syscollector_collection_sets_internal]...'
ALTER TABLE [dbo].[syscollector_collection_sets_internal] ADD dump_on_any_error bit default 0
END
IF (NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name = N'dump_on_codes' AND id = OBJECT_ID(N'[dbo].[syscollector_collection_sets_internal]')))
BEGIN
PRINT 'Altering table [dbo].[syscollector_collection_sets_internal]...'
ALTER TABLE [dbo].[syscollector_collection_sets_internal] ADD dump_on_codes nvarchar(max) NULL
END
END
GO
IF (NOT OBJECT_ID(N'[dbo].[syscollector_collection_sets]', 'V') IS NULL)
BEGIN
PRINT 'Dropping view [dbo].[syscollector_collection_sets]...'
DROP VIEW [dbo].[syscollector_collection_sets]
END
GO
PRINT 'Creating view [dbo].[syscollector_collection_sets]...'
GO
CREATE VIEW [dbo].[syscollector_collection_sets]
AS
SELECT
s.collection_set_id,
s.collection_set_uid,
CASE
WHEN s.name_id IS NULL THEN s.name
ELSE FORMATMESSAGE(s.name_id)
END AS name,
s.target,
s.is_system,
s.is_running,
s.collection_mode,
s.proxy_id,
s.schedule_uid,
s.collection_job_id,
s.upload_job_id,
s.logging_level,
s.days_until_expiration,
CASE
WHEN s.description_id IS NULL THEN s.description
ELSE FORMATMESSAGE(s.description_id)
END AS description,
s.dump_on_any_error,
s.dump_on_codes
FROM
[dbo].[syscollector_collection_sets_internal] AS s
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_verify_collection_set]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_verify_collection_set]...'
DROP PROCEDURE [dbo].[sp_syscollector_verify_collection_set]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_verify_collection_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_verify_collection_set]
@collection_set_id int = NULL OUTPUT,
@name sysname = NULL OUTPUT
AS
BEGIN
IF (@name IS NOT NULL)
BEGIN
-- Remove any leading/trailing spaces from parameters
SET @name = NULLIF(LTRIM(RTRIM(@name)), N'')
END
IF (@collection_set_id IS NULL AND @name IS NULL)
BEGIN
RAISERROR(14624, -1, -1, '@collection_set_id, @name')
RETURN(1)
END
IF (@collection_set_id IS NOT NULL AND @name IS NOT NULL)
BEGIN
IF (NOT EXISTS(SELECT *
FROM dbo.syscollector_collection_sets
WHERE collection_set_id = @collection_set_id
AND name = @name))
BEGIN
DECLARE @errMsg NVARCHAR(196)
SELECT @errMsg = CONVERT(NVARCHAR(36), @collection_set_id) + ', ' + @name
RAISERROR(14262, -1, -1, '@collection_set_id, @name', @errMsg)
RETURN(1)
END
END
-- Check id
ELSE IF (@collection_set_id IS NOT NULL)
BEGIN
SELECT @name = name
FROM dbo.syscollector_collection_sets
WHERE (collection_set_id = @collection_set_id)
-- the view would take care of all the permissions issues.
IF (@name IS NULL)
BEGIN
DECLARE @collection_set_id_as_char VARCHAR(36)
SELECT @collection_set_id_as_char = CONVERT(VARCHAR(36), @collection_set_id)
RAISERROR(14262, -1, -1, '@collection_set_id', @collection_set_id_as_char)
RETURN(1) -- Failure
END
END
-- Check name
ELSE IF (@name IS NOT NULL)
BEGIN
-- get the corresponding collection_set_id (if the collection set exists)
SELECT @collection_set_id = collection_set_id
FROM dbo.syscollector_collection_sets
WHERE (name = @name)
-- the view would take care of all the permissions issues.
IF (@collection_set_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
END
RETURN (0)
END
GO
-- Create one schedule that starts when SQL Agent starts so that all continuous
-- collection jobs can attach to it, the schedule has to be accessible to the internal dc user that owns agent objects
-- EXECUTE AS USER = 'MS_DataCollectorInternalUser';
IF (NOT EXISTS (SELECT * FROM sysschedules_localserver_view WHERE name = N'RunAsSQLAgentServiceStartSchedule'))
BEGIN
EXEC dbo.sp_add_schedule
@schedule_name = N'RunAsSQLAgentServiceStartSchedule',
@freq_type = 0x40, -- FREQTYPE_AUTOSTART
@freq_interval = 1
END
-- REVERT;
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_create_jobs]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_create_jobs]...'
DROP PROCEDURE [dbo].[sp_syscollector_create_jobs]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_create_jobs]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_create_jobs]
@collection_set_id int,
@collection_set_uid uniqueidentifier,
@collection_set_name sysname,
@proxy_id int = NULL,
@schedule_id int = NULL,
@collection_mode smallint,
@collection_job_id uniqueidentifier OUTPUT,
@upload_job_id uniqueidentifier OUTPUT
AS
BEGIN
SET NOCOUNT ON
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_syscollector_create_jobs
ELSE
BEGIN TRANSACTION
BEGIN TRY
-- job step names and commands shared between collection modes
DECLARE @collection_set_id_as_char nvarchar(36)
DECLARE @collection_step_command nvarchar(512)
DECLARE @upload_step_command nvarchar(512)
DECLARE @autostop_step_command nvarchar(512)
DECLARE @purge_step_command nvarchar(1024)
DECLARE @collection_step_name sysname
DECLARE @upload_step_name sysname
DECLARE @autostop_step_name sysname
DECLARE @purge_step_name sysname
DECLARE @job_name sysname
DECLARE @job_id uniqueidentifier
DECLARE @description nvarchar(512)
IF(@collection_set_id IS NOT NULL)
BEGIN
SET @collection_set_id_as_char = CONVERT(NVARCHAR(36), @collection_set_id)
SET @collection_step_command =
N'dcexec -c -s ' + @collection_set_id_as_char + N' -i "$(ESCAPE_DQUOTE(MACH))\$(ESCAPE_DQUOTE(INST))"' +
N' -m ' + CONVERT(NVARCHAR(36), @collection_mode);
SET @upload_step_command =
N'dcexec -u -s ' + @collection_set_id_as_char + N' -i "$(ESCAPE_DQUOTE(MACH))\$(ESCAPE_DQUOTE(INST))"';
SET @autostop_step_command =
N'exec dbo.sp_syscollector_stop_collection_set @collection_set_id=' + @collection_set_id_as_char
+ N', @stop_collection_job = 0'; -- do not stop the collection job, otherwise you will abort yourself!
SET @purge_step_command =
N'
EXEC [dbo].[sp_syscollector_purge_collection_logs]
'
END
-- verify that the proxy_id exists
IF (@proxy_id IS NOT NULL)
BEGIN
DECLARE @proxy_name sysname
DECLARE @retVal int
-- this will throw an error of proxy_id does not exist
EXEC @retVal = msdb.dbo.sp_verify_proxy_identifiers '@proxy_name', '@proxy_id', @proxy_name OUTPUT, @proxy_id OUTPUT
IF (@retVal <> 0)
RETURN (0)
END
-- add jobs, job steps and attach schedule separately for different modes
IF (@collection_mode = 1) -- non-cached mode
BEGIN
-- create 1 job and 2 steps, first for collection & upload, second for log purging
SET @job_name = N'collection_set_' + @collection_set_id_as_char + '_noncached_collect_and_upload'
SET @collection_step_name = @job_name + '_collect'
SET @upload_step_name = @job_name + '_upload'
SET @purge_step_name = @job_name + '_purge_logs'
SET @description = N'Data Collector job for collection set ' + QUOTENAME(@collection_set_name)
-- add agent job and job server
EXEC dbo.sp_add_job
@job_name = @job_name,
@category_id = 8, -- N'Data Collector'
@enabled = 0,
@description = @description,
@job_id = @job_id OUTPUT
EXEC dbo.sp_add_jobserver
@job_id = @job_id,
@server_name = N'(local)'
-- add both collect and upload job steps to the same job
EXEC dbo.sp_add_jobstep
@job_id = @job_id,
@step_name = @collection_step_name,
@subsystem = 'CMDEXEC',
@command = @collection_step_command,
@on_success_action = 3, -- go to the next job step (purge the log)
@on_fail_action = 2, -- quit with failure
@proxy_id = @proxy_id,
@flags = 16 -- Write log to table (append to existing history)
EXEC dbo.sp_add_jobstep
@job_id = @job_id,
@step_name = @purge_step_name,
@subsystem = 'TSQL',
@database_name = 'msdb',
@command = @purge_step_command,
@on_success_action = 3, -- go to the next job step (upload)
@on_fail_action = 3, -- go to the next job step (upload)
@proxy_id = NULL,
@flags = 16 -- write log to table (append to existing history)
EXEC dbo.sp_add_jobstep
@job_id = @job_id,
@step_name = @upload_step_name,
@subsystem = 'CMDEXEC',
@command = @upload_step_command,
@on_success_action = 1, -- quit with success
@on_fail_action = 2, -- quit with failure
@proxy_id = @proxy_id,
@flags = 16 -- Write log to table (append to existing history)
IF @schedule_id IS NOT NULL
BEGIN
-- attach the schedule
EXEC dbo.sp_attach_schedule
@job_id = @job_id,
@schedule_id = @schedule_id
END
SET @upload_job_id = @job_id
SET @collection_job_id = @job_id
END
IF (@collection_mode = 0) -- cached mode
BEGIN
-- create 2 jobs for collect and upload
-- add to collect job an extra step that autostops collection called in case collect job fails
DECLARE @upload_job_name sysname
DECLARE @collection_job_name sysname
SET @upload_job_name = N'collection_set_' + @collection_set_id_as_char + '_upload'
SET @collection_job_name = N'collection_set_' + @collection_set_id_as_char + '_collection'
SET @collection_step_name = @collection_job_name + '_collect'
SET @autostop_step_name = @collection_job_name + '_autostop'
SET @upload_step_name = @upload_job_name + '_upload'
SET @purge_step_name = @upload_job_name + '_purge_logs'
-- modify the collection step to pass in the stop event name passed in by agent
SET @collection_step_command = @collection_step_command + N' -e $' + N'(ESCAPE_NONE(' + N'STOPEVENT))'
-- add agent job and job server
EXEC dbo.sp_add_job
@job_name = @upload_job_name,
@category_id = 8, -- N'Data Collector'
@enabled = 0,
@job_id = @upload_job_id OUTPUT
EXEC dbo.sp_add_jobserver
@job_id = @upload_job_id,
@server_name = N'(local)'
EXEC dbo.sp_add_job
@job_name = @collection_job_name,
@category_id = 8, -- N'Data Collector'
@enabled = 0,
@job_id = @collection_job_id OUTPUT
EXEC dbo.sp_add_jobserver
@job_id = @collection_job_id,
@server_name = N'(local)'
-- add upload job step to upload job and collection job
-- step to collection job separately
EXEC dbo.sp_add_jobstep
@job_id = @upload_job_id,
@step_name = @purge_step_name,
@subsystem = 'TSQL',
@database_name = 'msdb',
@command = @purge_step_command,
@on_success_action = 3, -- go to next job step (upload)
@on_fail_action = 3, -- go to next job step (upload)
@proxy_id = NULL,
@flags = 16 -- write log to table (append to existing history)
EXEC dbo.sp_add_jobstep
@job_id = @upload_job_id,
@step_name = @upload_step_name,
@subsystem = 'CMDEXEC',
@command = @upload_step_command,
@on_success_action = 1, -- quit with success
@on_fail_action = 2, -- quit with failure
@proxy_id = @proxy_id
EXEC dbo.sp_add_jobstep
@job_id = @collection_job_id,
@step_name = @collection_step_name,
@subsystem = 'CMDEXEC',
@command = @collection_step_command,
@on_success_action = 1, -- quit with success
@on_fail_action = 3, -- go to next job step (auto-stop)
@proxy_id = @proxy_id,
@flags = 80 -- 16 (write log to table (append to existing history)
-- + 64 (create a stop event and pass it to the command line)
EXEC dbo.sp_add_jobstep
@job_id = @collection_job_id,
@step_name = @autostop_step_name,
@subsystem = 'TSQL',
@database_name = 'msdb',
@command = @autostop_step_command,
@on_success_action = 2, -- quit with failure
@on_fail_action = 2, -- quit with failure
@proxy_id = NULL,
@flags = 16 -- write log to table (append to existing history)
-- attach the input schedule to the upload job
EXEC dbo.sp_attach_schedule
@job_id = @upload_job_id,
@schedule_id = @schedule_id
-- attach the RunAsSQLAgentServiceStartSchedule to the collection job
EXEC dbo.sp_attach_schedule
@job_id = @collection_job_id,
@schedule_name = N'RunAsSQLAgentServiceStartSchedule'
END
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_syscollector_create_jobs
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_create_collection_set]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_create_collection_set]...'
DROP PROCEDURE [dbo].[sp_syscollector_create_collection_set]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_create_collection_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_create_collection_set]
@name sysname,
@target nvarchar(128) = NULL,
@collection_mode smallint = 0, -- 0: cached, 1: non-cached
@days_until_expiration smallint = 730, -- two years
@proxy_id int = NULL, -- mutual exclusive; must specify either proxy_id or proxy_name to identify the proxy
@proxy_name sysname = NULL,
@schedule_uid uniqueidentifier = NULL,
@schedule_name sysname = NULL, -- mutual exclusive; must specify either schedule_uid or schedule_name to identify the schedule
@logging_level smallint = 1,
@description nvarchar(4000) = NULL,
@collection_set_id int OUTPUT,
@collection_set_uid uniqueidentifier = NULL OUTPUT
WITH EXECUTE AS OWNER -- 'MS_DataCollectorInternalUser'
AS
BEGIN
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_create_collection_set
ELSE
BEGIN TRANSACTION
BEGIN TRY
-- Security check (role membership)
EXECUTE AS CALLER;
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
REVERT;
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN (1)
END
REVERT;
-- Remove any leading/trailing spaces from parameters
SET @name = NULLIF(LTRIM(RTRIM(@name)), N'')
SET @proxy_name = NULLIF(LTRIM(RTRIM(@proxy_name)), N'')
SET @schedule_name = NULLIF(LTRIM(RTRIM(@schedule_name)), N'')
SET @target = NULLIF(LTRIM(RTRIM(@target)), N'')
SET @description = LTRIM(RTRIM(@description))
IF (@name IS NULL)
BEGIN
RAISERROR(21263, -1, -1, '@name')
RETURN (1)
END
-- can't have both name and uid for the schedule
IF (@schedule_uid IS NOT NULL) AND (@schedule_name IS NOT NULL)
BEGIN
RAISERROR(14373, -1, -1, '@schedule_uid', '@schedule_name')
RETURN (1)
END
-- Execute the check for the schedule as caller to ensure only schedules owned by caller can be attached
EXECUTE AS CALLER;
DECLARE @schedule_id int
IF (@schedule_uid IS NOT NULL)
BEGIN
SElECT @schedule_id = schedule_id FROM sysschedules_localserver_view WHERE @schedule_uid = schedule_uid
IF (@schedule_id IS NULL)
BEGIN
DECLARE @schedule_uid_as_char VARCHAR(36)
SELECT @schedule_uid_as_char = CONVERT(VARCHAR(36), @schedule_uid)
REVERT;
RAISERROR(14262, -1, -1, N'@schedule_uid', @schedule_uid_as_char)
RETURN (1)
END
END
ELSE IF (@schedule_name IS NOT NULL)
BEGIN
SELECT @schedule_id = schedule_id, @schedule_uid = schedule_uid FROM sysschedules_localserver_view WHERE name = @schedule_name
IF (@schedule_id IS NULL)
BEGIN
REVERT;
RAISERROR(14262, -1, -1, N'@schedule_name', @schedule_name)
RETURN (1)
END
END
REVERT;
-- if collection_mode is cached, make sure schedule_id is not null
IF (@collection_mode = 0 AND @schedule_id IS NULL)
BEGIN
RAISERROR(14683, -1, -1)
RETURN (1)
END
IF (@proxy_id IS NOT NULL) OR (@proxy_name IS NOT NULL)
BEGIN
-- check if the proxy exists
EXEC sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
-- check if proxy_id is granted to dc_admin
IF (@proxy_id NOT IN (SELECT proxy_id
FROM sysproxylogin
WHERE sid = USER_SID(USER_ID('dc_admin'))
)
)
BEGIN
RAISERROR(14719, -1, -1, N'dc_admin')
RETURN (1)
END
END
IF (@collection_mode < 0 OR @collection_mode > 1)
BEGIN
RAISERROR(14266, -1, -1, '@collection_mode', '0, 1')
RETURN (1)
END
IF (@logging_level < 0 OR @logging_level > 2)
BEGIN
RAISERROR(14266, -1, -1, '@logging_level', '0, 1, or 2')
RETURN (1)
END
IF (@collection_set_uid IS NULL)
BEGIN
SET @collection_set_uid = NEWID()
END
IF (@days_until_expiration < 0)
BEGIN
RAISERROR(14266, -1, -1, '@days_until_expiration', '>= 0')
RETURN (1)
END
INSERT INTO [dbo].[syscollector_collection_sets_internal]
(
collection_set_uid,
schedule_uid,
name,
target,
is_running,
proxy_id,
is_system,
upload_job_id,
collection_job_id,
collection_mode,
logging_level,
days_until_expiration,
description
)
VALUES
(
@collection_set_uid,
@schedule_uid,
@name,
@target,
0,
@proxy_id,
0,
NULL,
NULL,
@collection_mode,
@logging_level,
@days_until_expiration,
@description
)
SET @collection_set_id = SCOPE_IDENTITY()
IF (@collection_set_id IS NULL)
BEGIN
DECLARE @collection_set_id_as_char VARCHAR(36)
SELECT @collection_set_id_as_char = CONVERT(VARCHAR(36), @collection_set_id)
RAISERROR(14262, -1, -1, '@collection_set_id', @collection_set_id_as_char)
RETURN (1)
END
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_create_collection_set
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_update_job_proxy]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_update_job_proxy]...'
DROP PROCEDURE [dbo].[sp_syscollector_update_job_proxy]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_update_job_proxy]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_update_job_proxy]
@job_id uniqueidentifier,
@proxy_id int = NULL,
@proxy_name sysname = NULL
AS
BEGIN
-- update the proxy id for the all job steps
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_syscollector_update_proxy
ELSE
BEGIN TRANSACTION
BEGIN TRY
DECLARE @step_id INT
DECLARE cursor_job_steps CURSOR FOR
SELECT step_id FROM dbo.sysjobsteps WHERE job_id = @job_id AND subsystem = N'CMDEXEC'
OPEN cursor_job_steps
FETCH NEXT FROM cursor_job_steps INTO @step_id
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC dbo.sp_update_jobstep
@job_id = @job_id,
@step_id = @step_id,
@proxy_id = @proxy_id,
@proxy_name = @proxy_name
FETCH NEXT FROM cursor_job_steps INTO @step_id
END
CLOSE cursor_job_steps
DEALLOCATE cursor_job_steps
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_syscollector_update_proxy
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_update_collection_set_internal]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_update_collection_set_internal]...'
DROP PROCEDURE [dbo].[sp_syscollector_update_collection_set_internal]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_update_collection_set_internal]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_update_collection_set_internal]
@collection_set_id int,
@collection_set_uid uniqueidentifier,
@name sysname,
@new_name sysname,
@target nvarchar(128),
@collection_mode smallint,
@days_until_expiration smallint,
@proxy_id int,
@proxy_name sysname,
@schedule_uid uniqueidentifier,
@schedule_name sysname,
@logging_level smallint,
@description nvarchar(4000),
@schedule_id int,
@old_collection_mode smallint,
@old_proxy_id int,
@old_collection_job_id uniqueidentifier,
@old_upload_job_id uniqueidentifier
AS
BEGIN
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_update_collection_set
ELSE
BEGIN TRANSACTION
BEGIN TRY
DECLARE @old_upload_schedule_id int
DECLARE @old_upload_schedule_uid uniqueidentifier
SELECT @old_upload_schedule_id = sv.schedule_id,
@old_upload_schedule_uid = cs.schedule_uid
FROM dbo.syscollector_collection_sets cs
JOIN sysschedules_localserver_view sv ON (cs.schedule_uid = sv.schedule_uid)
WHERE collection_set_id = @collection_set_id
-- update job names, schedule, and collection mode in a transaction to maintain a consistent state in case of failures
IF (@collection_mode IS NOT NULL AND @collection_mode != @old_collection_mode)
BEGIN
IF (@schedule_id IS NULL)
BEGIN
-- if no schedules is supplied as a parameter to this update SP,
-- we can use the one that is already in the collection set table
SET @schedule_uid = @old_upload_schedule_uid
SELECT @schedule_id = schedule_id
FROM sysschedules_localserver_view
WHERE @schedule_uid = schedule_uid
END
IF (@schedule_name IS NOT NULL AND @schedule_name = N'')
BEGIN
SET @schedule_id = NULL
END
-- make sure there exists a schedule we can use
IF (@old_collection_mode = 1 AND @schedule_id IS NULL) -- a switch from non-cached to cached mode require a schedule
BEGIN
-- no schedules specified in input or collection set table, raise error
RAISERROR(14683, -1, -1)
RETURN (1)
END
-- Only update the jobs if we have jobs already created. Otherwise the right
-- jobs will be created when the collection set starts for the first time.
IF (@old_collection_job_id IS NOT NULL AND @old_upload_job_id IS NOT NULL)
BEGIN
-- create new jobs
DECLARE @collection_job_id uniqueidentifier
DECLARE @upload_job_id uniqueidentifier
DECLARE @collection_set_name sysname;
SET @collection_set_name = ISNULL(@new_name, @name);
EXEC [dbo].[sp_syscollector_create_jobs]
@collection_set_id = @collection_set_id,
@collection_set_uid = @collection_set_uid,
@collection_set_name = @collection_set_name,
@proxy_id = @proxy_id,
@schedule_id = @schedule_id,
@collection_mode = @collection_mode,
@collection_job_id = @collection_job_id OUTPUT,
@upload_job_id = @upload_job_id OUTPUT
UPDATE [dbo].[syscollector_collection_sets_internal]
SET
upload_job_id = @upload_job_id,
collection_job_id = @collection_job_id
WHERE @collection_set_id = collection_set_id
-- drop old upload and collection jobs
EXEC dbo.sp_syscollector_delete_jobs
@collection_job_id = @old_collection_job_id,
@upload_job_id = @old_upload_job_id,
@schedule_id = @old_upload_schedule_id,
@collection_mode = @old_collection_mode
END
END
ELSE -- collection mode unchanged, we do not have to recreate the jobs
BEGIN
-- we need to update the proxy id for all job steps
IF (@old_proxy_id <> @proxy_id) OR (@old_proxy_id IS NULL AND @proxy_id IS NOT NULL)
BEGIN
IF (@old_collection_job_id IS NOT NULL)
BEGIN
EXEC dbo.sp_syscollector_update_job_proxy
@job_id = @old_collection_job_id,
@proxy_id = @proxy_id
END
IF (@old_upload_job_id IS NOT NULL)
BEGIN
EXEC dbo.sp_syscollector_update_job_proxy
@job_id = @old_upload_job_id,
@proxy_id = @proxy_id
END
END
IF (@proxy_name = N'' AND @old_proxy_id IS NOT NULL)
BEGIN
IF (@old_collection_job_id IS NOT NULL)
BEGIN
EXEC dbo.sp_syscollector_update_job_proxy
@job_id = @old_collection_job_id,
@proxy_name = @proxy_name
END
IF (@old_upload_job_id IS NOT NULL)
BEGIN
EXEC dbo.sp_syscollector_update_job_proxy
@job_id = @old_upload_job_id,
@proxy_name = @proxy_name
END
END
-- need to update the schedule
IF (@old_upload_schedule_id <> @schedule_id) OR (@old_upload_schedule_id IS NULL AND @schedule_id IS NOT NULL)
BEGIN
-- detach the old schedule
IF (@old_upload_job_id IS NOT NULL) AND (@old_upload_schedule_id IS NOT NULL)
BEGIN
EXEC dbo.sp_detach_schedule
@job_id = @old_upload_job_id,
@schedule_id = @old_upload_schedule_id,
@delete_unused_schedule = 0
END
-- attach the new schedule
IF (@old_upload_job_id IS NOT NULL)
BEGIN
EXEC dbo.sp_attach_schedule
@job_id = @old_upload_job_id,
@schedule_id = @schedule_id
END
END
-- special case - remove the existing schedule
IF (@schedule_name = N'') AND (@old_upload_schedule_id IS NOT NULL)
BEGIN
EXEC dbo.sp_detach_schedule
@job_id = @old_upload_job_id,
@schedule_id = @old_upload_schedule_id,
@delete_unused_schedule = 0
END
END
-- after the all operations succeed, update the sollection_sets table
DECLARE @new_proxy_id int
SET @new_proxy_id = @proxy_id
IF (@proxy_name = N'') SET @new_proxy_id = NULL
UPDATE [dbo].[syscollector_collection_sets_internal]
SET
name = ISNULL(@new_name, name),
target = ISNULL(@target, target),
proxy_id = @new_proxy_id,
collection_mode = ISNULL(@collection_mode, collection_mode),
logging_level = ISNULL(@logging_level, logging_level),
days_until_expiration = ISNULL(@days_until_expiration, days_until_expiration)
WHERE @collection_set_id = collection_set_id
IF (@schedule_uid IS NOT NULL OR @schedule_name IS NOT NULL)
BEGIN
IF (@schedule_name = N'') SET @schedule_uid = NULL
UPDATE [dbo].[syscollector_collection_sets_internal]
SET schedule_uid = @schedule_uid
WHERE @collection_set_id = collection_set_id
END
IF (@description IS NOT NULL)
BEGIN
IF (@description = N'') SET @description = NULL
UPDATE [dbo].[syscollector_collection_sets_internal]
SET description = @description
WHERE @collection_set_id = collection_set_id
END
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_update_collection_set
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_update_collection_set]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_update_collection_set]...'
DROP PROCEDURE [dbo].[sp_syscollector_update_collection_set]
END
GO
-- Updates a collection set. These are the steps involved
-- 1- Security checks
-- 2- Stop the collection set if currently running (sp_syscollector_stop_collection_set)
-- 3- Perform the actual update transactionally (sp_syscollector_update_collection_set_internal)
-- 4- Restart the collection set if it was running (sp_syscollector_start_collection_set
PRINT 'Creating procedure [dbo].[sp_syscollector_update_collection_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_update_collection_set]
@collection_set_id int = NULL,
@name sysname = NULL,
@new_name sysname = NULL,
@target nvarchar(128) = NULL,
@collection_mode smallint = NULL, -- 0: cached, 1: non-cached
@days_until_expiration smallint = NULL,
@proxy_id int = NULL, -- mutual exclusive; must specify either proxy_id or proxy_name to identify the proxy
@proxy_name sysname = NULL, -- @proxy_name = N'' is a special case to allow change of an existing proxy with NULL
@schedule_uid uniqueidentifier = NULL, -- mutual exclusive; must specify either schedule_uid or schedule_name to identify the schedule
@schedule_name sysname = NULL, -- @schedule_name = N'' is a special case to allow change of an existing schedule with NULL
@logging_level smallint = NULL,
@description nvarchar(4000) = NULL -- @description = N'' is a special case to allow change of an existing description with NULL
WITH EXECUTE AS OWNER -- 'MS_DataCollectorInternalUser'
AS
BEGIN
-- Security checks will be performed against caller's security context
EXECUTE AS CALLER;
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
REVERT;
RAISERROR(14677, -1, -1, 'dc_operator')
RETURN (1)
END
-- Security checks (restrict functionality for non-dc_admin-s)
IF (((NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1)) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
AND (@new_name IS NOT NULL))
BEGIN
REVERT;
RAISERROR(14676, -1, -1, '@new_name', 'dc_admin')
RETURN (1)
END
IF (((NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1)) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
AND (@target IS NOT NULL))
BEGIN
REVERT;
RAISERROR(14676, -1, -1, '@target', 'dc_admin')
RETURN (1)
END
IF (((NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1)) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
AND (@proxy_id IS NOT NULL))
BEGIN
REVERT;
RAISERROR(14676, -1, -1, '@proxy_id', 'dc_admin')
RETURN (1)
END
IF (((NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1)) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
AND (@collection_mode IS NOT NULL))
BEGIN
REVERT;
RAISERROR(14676, -1, -1, '@collection_mode', 'dc_admin')
RETURN (1)
END
IF (((NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1)) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
AND (@description IS NOT NULL))
BEGIN
REVERT;
RAISERROR(14676, -1, -1, '@description', 'dc_admin')
RETURN (1)
END
IF (((NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1)) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
AND (@days_until_expiration IS NOT NULL))
BEGIN
REVERT;
RAISERROR(14676, -1, -1, '@days_until_expiration', 'dc_admin')
RETURN (1) -- Failure
END
-- Security checks done, reverting now to internal data collector user security context
REVERT;
-- check for inconsistencies/errors in the parameters
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collection_set @collection_set_id OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
IF (@collection_mode IS NOT NULL AND (@collection_mode < 0 OR @collection_mode > 1))
BEGIN
RAISERROR(14266, -1, -1, '@collection_mode', '0, 1')
RETURN (1)
END
IF (@logging_level IS NOT NULL AND (@logging_level < 0 OR @logging_level > 2))
BEGIN
RAISERROR(14266, -1, -1, '@logging_level', '0, 1, or 2')
RETURN(1)
END
IF (LEN(@new_name) = 0)
BEGIN
RAISERROR(21263, -1, -1, '@new_name')
RETURN(1) -- Failure
END
-- Remove any leading/trailing spaces from parameters
SET @target = NULLIF(LTRIM(RTRIM(@target)), N'')
SET @new_name = NULLIF(LTRIM(RTRIM(@new_name)), N'')
SET @description = LTRIM(RTRIM(@description))
DECLARE @is_system bit
DECLARE @is_running bit
DECLARE @collection_set_uid uniqueidentifier
DECLARE @old_collection_mode smallint
DECLARE @old_upload_job_id uniqueidentifier
DECLARE @old_collection_job_id uniqueidentifier
DECLARE @old_proxy_id int
SELECT @is_running = is_running,
@is_system = is_system,
@collection_set_uid = collection_set_uid,
@old_collection_mode = collection_mode,
@old_collection_job_id = collection_job_id,
@old_upload_job_id = upload_job_id,
@old_proxy_id = proxy_id
FROM dbo.syscollector_collection_sets
WHERE collection_set_id = @collection_set_id
IF (@is_system = 1 AND (
@new_name IS NOT NULL OR
@description IS NOT NULL))
BEGIN
-- cannot update, delete, or add new collection items to a system collection set
RAISERROR(14696, -1, -1);
RETURN (1)
END
IF (@proxy_id IS NOT NULL) OR (@proxy_name IS NOT NULL AND @proxy_name <> N'')
BEGIN
-- verify the proxy exists
EXEC sp_verify_proxy_identifiers '@proxy_name',
'@proxy_id',
@proxy_name OUTPUT,
@proxy_id OUTPUT
-- check if proxy_id is granted to dc_admin
IF (@proxy_id NOT IN (SELECT proxy_id
FROM sysproxylogin
WHERE sid = USER_SID(USER_ID('dc_admin'))
)
)
BEGIN
RAISERROR(14719, -1, -1, N'dc_admin')
RETURN (1)
END
END
ELSE -- if no proxy_id provided, get the existing proxy_id, might need it later to create new jobs
BEGIN
SET @proxy_id = @old_proxy_id
END
-- can't have both uid and name passed for the schedule
IF (@schedule_uid IS NOT NULL) AND (@schedule_name IS NOT NULL AND @schedule_name <> N'')
BEGIN
RAISERROR(14373, -1, -1, '@schedule_uid', '@schedule_name')
RETURN (1)
END
-- check if it attempts to remove a schedule when the collection mode is cached
IF (@schedule_name = N'' AND @collection_mode = 0) OR
(@collection_mode IS NULL AND @old_collection_mode = 0 AND @schedule_name = N'')
BEGIN
RAISERROR(14683, -1, -1)
RETURN (1)
END
-- Execute the check for the schedule as caller to ensure only schedules owned by caller can be attached
EXECUTE AS CALLER;
DECLARE @schedule_id int
SET @schedule_id = NULL
IF (@schedule_uid IS NOT NULL)
BEGIN
SElECT @schedule_id = schedule_id FROM sysschedules_localserver_view WHERE @schedule_uid = schedule_uid
IF (@schedule_id IS NULL)
BEGIN
DECLARE @schedule_uid_as_char VARCHAR(36)
SELECT @schedule_uid_as_char = CONVERT(VARCHAR(36), @schedule_uid)
REVERT;
RAISERROR(14262, -1, -1, N'@schedule_uid', @schedule_uid_as_char)
RETURN (1)
END
END
ELSE IF (@schedule_name IS NOT NULL AND @schedule_name <> N'') -- @schedule_name is not null
BEGIN
SELECT @schedule_id = schedule_id, @schedule_uid = schedule_uid FROM sysschedules_localserver_view WHERE name = @schedule_name
IF (@schedule_id IS NULL)
BEGIN
REVERT;
RAISERROR(14262, -1, -1, N'@schedule_name', @schedule_name)
RETURN (1)
END
END
REVERT;
-- Stop the collection set if it is currently running
IF (@is_running = 1 AND (
@new_name IS NOT NULL OR
@target IS NOT NULL OR
@proxy_id IS NOT NULL OR
@logging_level IS NOT NULL OR
@collection_mode IS NOT NULL))
BEGIN
EXEC @retVal = sp_syscollector_stop_collection_set @collection_set_id = @collection_set_id
IF (@retVal <> 0)
RETURN (1)
END
-- Passed all necessary checks, go ahead with the update
EXEC @retVal = sp_syscollector_update_collection_set_internal
@collection_set_id = @collection_set_id,
@collection_set_uid = @collection_set_uid,
@name = @name,
@new_name = @new_name,
@target = @target,
@collection_mode = @collection_mode,
@days_until_expiration = @days_until_expiration,
@proxy_id = @proxy_id,
@proxy_name = @proxy_name,
@schedule_uid = @schedule_uid,
@schedule_name = @schedule_name,
@logging_level = @logging_level,
@description = @description,
@schedule_id = @schedule_id,
@old_collection_mode = @old_collection_mode,
@old_proxy_id = @old_proxy_id,
@old_collection_job_id = @old_collection_job_id,
@old_upload_job_id = @old_upload_job_id
IF (@retVal <> 0)
RETURN (1)
-- Restart the collection set if it has been already running
IF (@is_running = 1)
BEGIN
EXEC @retVal = sp_syscollector_start_collection_set
@collection_set_id = @collection_set_id
IF (@retVal <> 0)
RETURN (1)
END
RETURN (0)
END
GO
IF (NOT OBJECT_ID('dbo.sp_syscollector_configure_sql_dumper', 'P') IS NULL)
BEGIN
DROP PROCEDURE [dbo].[sp_syscollector_configure_sql_dumper]
END
GO
PRINT ''
PRINT 'Creating procedure [dbo].[sp_syscollector_configure_sql_dumper]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_configure_sql_dumper]
@collection_set_id int = NULL,
@name sysname = NULL,
@dump_on_any_error bit = NULL, -- configure SQL dumper to dump on any SSIS errors
@dump_on_codes nvarchar(max) = NULL -- configure SQL dumper to dump when we hit one of the specified SSIS errors. Set to N'' to remove the codes.
AS
BEGIN
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN(1) -- Failure
END
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collection_set @collection_set_id OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
DECLARE @is_running bit
SELECT @is_running = is_running
FROM dbo.syscollector_collection_sets
WHERE collection_set_id = @collection_set_id
IF (@is_running = 1)
BEGIN
RAISERROR(14711, 0, 1)
END
IF (@dump_on_codes = N'')
BEGIN
UPDATE [dbo].[syscollector_collection_sets_internal]
SET dump_on_codes = NULL
WHERE @collection_set_id = collection_set_id
END
ELSE IF (@dump_on_codes IS NOT NULL)
BEGIN
UPDATE [msdb].[dbo].[syscollector_collection_sets_internal]
SET dump_on_codes = @dump_on_codes
WHERE @collection_set_id = collection_set_id
END
IF (@dump_on_any_error IS NOT NULL)
BEGIN
UPDATE [msdb].[dbo].[syscollector_collection_sets_internal]
SET dump_on_any_error = @dump_on_any_error
WHERE @collection_set_id = collection_set_id
END
RETURN (0)
END
GO
---------------------------------------------------------------
-- Collector type
---------------------------------------------------------------
IF (OBJECT_ID(N'[dbo].[syscollector_collector_types_internal]', 'U') IS NULL)
BEGIN
PRINT 'Creating table [dbo].[syscollector_collector_types_internal]...'
CREATE TABLE [dbo].[syscollector_collector_types_internal] (
collector_type_uid uniqueidentifier NOT NULL,
name sysname NOT NULL,
parameter_schema xml NULL,
parameter_formatter xml NULL,
schema_collection sysname NULL,
collection_package_name sysname NOT NULL,
collection_package_folderid uniqueidentifier NOT NULL,
upload_package_name sysname NOT NULL,
upload_package_folderid uniqueidentifier NOT NULL,
is_system bit default 0 NOT NULL,
CONSTRAINT [PK_syscollector_collector_types_internal] PRIMARY KEY CLUSTERED (collector_type_uid ASC),
CONSTRAINT [UQ_syscollector_collection_types_internal_name] UNIQUE (name)
)
ALTER TABLE syscollector_collector_types_internal
ADD CONSTRAINT [FK_syscollector_collector_types_internal_upload_sysssispackages] FOREIGN KEY(upload_package_folderid, upload_package_name)
REFERENCES sysssispackages (folderid, [name])
ALTER TABLE syscollector_collector_types_internal
ADD CONSTRAINT [FK_syscollector_collector_types_internal_collection_sysssispackages] FOREIGN KEY(collection_package_folderid, collection_package_name)
REFERENCES sysssispackages (folderid, [name])
END
GO
-- [fn_syscollector_get_package_path]
-- This function returns the full path of a SSIS package given the package id
IF (NOT OBJECT_ID('[dbo].[fn_syscollector_get_package_path]', 'FN') IS NULL)
BEGIN
PRINT 'Dropping function [dbo].[fn_syscollector_get_package_path]...'
DROP FUNCTION [dbo].[fn_syscollector_get_package_path]
END
GO
PRINT 'Creating function [dbo].[fn_syscollector_get_package_path]...'
GO
CREATE FUNCTION [dbo].[fn_syscollector_get_package_path]
(
@package_id uniqueidentifier
)
RETURNS NVARCHAR(4000)
AS
BEGIN
IF @package_id IS NULL
RETURN NULL
DECLARE @package_path nvarchar(4000)
DECLARE @prevfolderid uniqueidentifier
DECLARE @folderid uniqueidentifier
DECLARE @package_name sysname
SET @package_path = ''
SELECT @package_name = name,
@folderid = folderid
FROM dbo.sysssispackages
WHERE id = @package_id
WHILE (@folderid != '00000000-0000-0000-0000-000000000000')
BEGIN
SET @prevfolderid = @folderid
DECLARE @foldername sysname
SELECT @foldername = foldername,
@folderid = parentfolderid
FROM dbo.sysssispackagefolders
WHERE folderid = @prevfolderid
SET @package_path = @foldername + N'\\' + @package_path
END
SET @package_path = N'\\' + @package_path + @package_name
RETURN @package_path
END
GO
IF (NOT OBJECT_ID(N'[dbo].[syscollector_collector_types]', 'V') IS NULL)
BEGIN
PRINT 'Dropping view [dbo].[syscollector_collector_types]...'
DROP VIEW [dbo].[syscollector_collector_types]
END
GO
PRINT 'Creating view [dbo].[syscollector_collector_types]...'
GO
CREATE VIEW [dbo].[syscollector_collector_types]
AS
SELECT
t.collector_type_uid,
t.name,
t.parameter_schema,
t.parameter_formatter,
s1.id AS collection_package_id,
dbo.fn_syscollector_get_package_path(s1.id) AS collection_package_path,
s1.name AS collection_package_name,
s2.id AS upload_package_id,
dbo.fn_syscollector_get_package_path(s2.id) AS upload_package_path,
s2.name AS upload_package_name,
t.is_system
FROM
[dbo].[syscollector_collector_types_internal] AS t,
sysssispackages s1,
sysssispackages s2
WHERE t.collection_package_folderid = s1.folderid
AND t.collection_package_name = s1.name
AND t.upload_package_folderid = s2.folderid
AND t.upload_package_name = s2.name
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_verify_collector_type]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_verify_collector_type]...'
DROP PROCEDURE [dbo].[sp_syscollector_verify_collector_type]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_verify_collector_type]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_verify_collector_type]
@collector_type_uid uniqueidentifier = NULL OUTPUT,
@name sysname = NULL OUTPUT
AS
BEGIN
IF (@name IS NOT NULL)
BEGIN
-- Remove any leading/trailing spaces from parameters
SET @name = NULLIF(LTRIM(RTRIM(@name)), N'')
END
IF (@collector_type_uid IS NULL AND @name IS NULL)
BEGIN
RAISERROR(14624, -1, -1, '@collector_type_uid, @name')
RETURN(1)
END
IF (@collector_type_uid IS NOT NULL AND @name IS NOT NULL)
BEGIN
IF (NOT EXISTS(SELECT *
FROM dbo.syscollector_collector_types
WHERE collector_type_uid = @collector_type_uid
AND name = @name))
BEGIN
DECLARE @errMsg NVARCHAR(196)
SELECT @errMsg = CONVERT(NVARCHAR(36), @collector_type_uid) + ', ' + @name
RAISERROR(14262, -1, -1, '@collector_type_uid, @name', @errMsg)
RETURN(1)
END
END
-- Check id
ELSE IF (@collector_type_uid IS NOT NULL)
BEGIN
SELECT @name = name
FROM dbo.syscollector_collector_types
WHERE (collector_type_uid = @collector_type_uid)
-- the view would take care of all the permissions issues.
IF (@name IS NULL)
BEGIN
DECLARE @collector_type_uid_as_char VARCHAR(36)
SELECT @collector_type_uid_as_char = CONVERT(VARCHAR(36), @collector_type_uid)
RAISERROR(14262, -1, -1, '@collector_type_uid', @collector_type_uid_as_char)
RETURN(1) -- Failure
END
END
-- Check name
ELSE IF (@name IS NOT NULL)
BEGIN
-- get the corresponding collector_type_uid (if the collector type exists)
SELECT @collector_type_uid = collector_type_uid
FROM dbo.syscollector_collector_types
WHERE (name = @name)
-- the view would take care of all the permissions issues.
IF (@collector_type_uid IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
END
RETURN (0)
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_create_collector_type]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_create_collector_type]...'
DROP PROCEDURE [dbo].[sp_syscollector_create_collector_type]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_create_collector_type]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_create_collector_type]
@collector_type_uid uniqueidentifier = NULL OUTPUT,
@name sysname,
@parameter_schema xml = NULL,
@parameter_formatter xml = NULL,
@collection_package_id uniqueidentifier,
@upload_package_id uniqueidentifier
AS
BEGIN
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_create_collector_type
ELSE
BEGIN TRANSACTION
BEGIN TRY
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN (1)
END
SET @name = NULLIF(LTRIM(RTRIM(@name)), N'')
IF (@name IS NULL)
BEGIN
RAISERROR(21263, -1, -1, '@name', @name)
RETURN (1)
END
IF (@collector_type_uid IS NULL)
BEGIN
SET @collector_type_uid = NEWID()
END
IF (NOT EXISTS(SELECT * from sysssispackages
WHERE @collection_package_id = id))
BEGIN
DECLARE @collection_package_id_as_char VARCHAR(36)
SELECT @collection_package_id_as_char = CONVERT(VARCHAR(36), @collection_package_id)
RAISERROR(14262, -1, -1, '@collection_package_id', @collection_package_id_as_char)
RETURN (1)
END
IF (NOT EXISTS(SELECT * from sysssispackages
WHERE @upload_package_id = id))
BEGIN
DECLARE @upload_package_id_as_char VARCHAR(36)
SELECT @upload_package_id_as_char = CONVERT(VARCHAR(36), @upload_package_id)
RAISERROR(14262, -1, -1, '@upload_package_id', @upload_package_id_as_char)
RETURN (1)
END
DECLARE @collection_package_name sysname
DECLARE @collection_package_folderid uniqueidentifier
DECLARE @upload_package_name sysname
DECLARE @upload_package_folderid uniqueidentifier
SELECT
@collection_package_name = name,
@collection_package_folderid = folderid
FROM sysssispackages
WHERE @collection_package_id = id
SELECT
@upload_package_name = name,
@upload_package_folderid = folderid
FROM sysssispackages
WHERE @upload_package_id = id
DECLARE @schema_collection sysname
IF (@parameter_schema IS NOT NULL)
BEGIN
SET @schema_collection = N'schema_collection_' + @name
WHILE (EXISTS (SELECT * FROM sys.xml_schema_collections WHERE name = @schema_collection))
BEGIN
SET @schema_collection = LEFT(@schema_collection, 119) + '_' + RIGHT(STR(FLOOR(RAND() * 100000000)),8)
END
DECLARE @retVal int
DECLARE @sql_string nvarchar(2048)
DECLARE @param_definition nvarchar(16)
SET @param_definition = N'@schema xml'
SET @sql_string = N'CREATE XML SCHEMA COLLECTION ' + QUOTENAME(@schema_collection, '[') + N' AS @schema; '
SET @sql_string = @sql_string + N'GRANT EXECUTE ON XML SCHEMA COLLECTION::[dbo].' + QUOTENAME(@schema_collection, '[') + N' TO dc_admin; '
SET @sql_string = @sql_string + N'GRANT VIEW DEFINITION ON XML SCHEMA COLLECTION::[dbo].' + QUOTENAME(@schema_collection, '[') + N' TO dc_admin; '
EXEC sp_executesql @sql_string, @param_definition, @schema = @parameter_schema
END
INSERT INTO [dbo].[syscollector_collector_types_internal]
(
collector_type_uid,
name,
parameter_schema,
parameter_formatter,
schema_collection,
collection_package_name,
collection_package_folderid,
upload_package_name,
upload_package_folderid
)
VALUES
(
@collector_type_uid,
@name,
@parameter_schema,
@parameter_formatter,
@schema_collection,
@collection_package_name,
@collection_package_folderid,
@upload_package_name,
@upload_package_folderid
)
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_create_collector_type
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_update_collector_type]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_update_collector_type]...'
DROP PROCEDURE [dbo].[sp_syscollector_update_collector_type]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_update_collector_type]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_update_collector_type]
@collector_type_uid uniqueidentifier = NULL,
@name sysname = NULL,
@parameter_schema xml = NULL,
@parameter_formatter xml = NULL,
@collection_package_id uniqueidentifier,
@upload_package_id uniqueidentifier
AS
BEGIN
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_update_collector_type
ELSE
BEGIN TRANSACTION
BEGIN TRY
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN (1)
END
-- Check the validity of the name/uid pair
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collector_type @collector_type_uid OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
DECLARE @old_parameter_schema xml
DECLARE @old_parameter_formatter xml
DECLARE @old_collection_package_id uniqueidentifier
DECLARE @old_upload_package_id uniqueidentifier
SELECT @old_parameter_schema = parameter_schema,
@old_parameter_formatter = parameter_formatter,
@old_collection_package_id = collection_package_id,
@old_upload_package_id = upload_package_id
FROM [dbo].[syscollector_collector_types]
WHERE name = @name
AND collector_type_uid = @collector_type_uid
IF (@collection_package_id IS NULL)
BEGIN
SET @collection_package_id = @old_collection_package_id
END
ELSE IF (NOT EXISTS(SELECT * from sysssispackages
WHERE @collection_package_id = id))
BEGIN
DECLARE @collection_package_id_as_char VARCHAR(36)
SELECT @collection_package_id_as_char = CONVERT(VARCHAR(36), @collection_package_id)
RAISERROR(14262, -1, -1, '@collection_package_id', @collection_package_id_as_char)
RETURN (1)
END
IF (@upload_package_id IS NULL)
BEGIN
SET @upload_package_id = @old_upload_package_id
END
ELSE IF (NOT EXISTS(SELECT * from sysssispackages
WHERE @upload_package_id = id))
BEGIN
DECLARE @upload_package_id_as_char VARCHAR(36)
SELECT @upload_package_id_as_char = CONVERT(VARCHAR(36), @upload_package_id)
RAISERROR(14262, -1, -1, '@upload_package_id', @upload_package_id_as_char)
RETURN (1)
END
DECLARE @collection_package_name sysname
DECLARE @collection_package_folderid uniqueidentifier
DECLARE @upload_package_name sysname
DECLARE @upload_package_folderid uniqueidentifier
SELECT
@collection_package_name = name,
@collection_package_folderid = folderid
FROM sysssispackages
WHERE @collection_package_id = id
SELECT
@upload_package_name = name,
@upload_package_folderid = folderid
FROM sysssispackages
WHERE @upload_package_id = id
DECLARE @schema_collection sysname
IF (@parameter_schema IS NULL)
BEGIN
SET @parameter_schema = @old_parameter_schema
END
ELSE
BEGIN
SELECT @schema_collection = schema_collection
FROM [dbo].[syscollector_collector_types_internal]
WHERE name = @name
AND collector_type_uid = @collector_type_uid
-- if a previous xml schema collection existed with the same name, drop it in favor of the new schema
IF (EXISTS (SELECT * FROM sys.xml_schema_collections WHERE name = @schema_collection))
BEGIN
DECLARE @sql_drop_schema nvarchar(512)
SET @sql_drop_schema = N'DROP XML SCHEMA COLLECTION ' + QUOTENAME(@schema_collection)
EXECUTE sp_executesql @sql_drop_schema
END
-- recreate it with the new schema
DECLARE @sql_create_schema nvarchar(2048)
DECLARE @param_definition nvarchar(16)
SET @param_definition = N'@schema xml'
SET @sql_create_schema = N'CREATE XML SCHEMA COLLECTION ' + QUOTENAME(@schema_collection) + N' AS @schema; '
SET @sql_create_schema = @sql_create_schema + N'GRANT EXECUTE ON XML SCHEMA COLLECTION::[dbo].' + QUOTENAME(@schema_collection) + N' TO dc_admin; '
SET @sql_create_schema = @sql_create_schema + N'GRANT VIEW DEFINITION ON XML SCHEMA COLLECTION::[dbo].' + QUOTENAME(@schema_collection) + N' TO dc_admin; '
EXEC sp_executesql @sql_create_schema, @param_definition, @schema = @parameter_schema
END
UPDATE [dbo].[syscollector_collector_types_internal]
SET parameter_schema = @parameter_schema,
parameter_formatter = @parameter_formatter,
schema_collection = @schema_collection,
collection_package_name = @collection_package_name,
collection_package_folderid = @collection_package_folderid,
upload_package_name = @upload_package_name,
upload_package_folderid = @upload_package_folderid
WHERE @collector_type_uid = collector_type_uid
AND @name = name
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_update_collector_type
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_validate_xml]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_validate_xml]...'
DROP PROCEDURE [dbo].[sp_syscollector_validate_xml]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_validate_xml]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_validate_xml]
@collector_type_uid uniqueidentifier = NULL,
@name sysname = NULL,
@parameters xml
AS
BEGIN
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collector_type @collector_type_uid OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
DECLARE @schema_collection sysname
SET @schema_collection = (SELECT schema_collection
FROM syscollector_collector_types_internal
WHERE @collector_type_uid = collector_type_uid)
IF (@schema_collection IS NULL)
BEGIN
RAISERROR(21263, -1, -1, '@schema_collection')
RETURN (1)
END
-- @sql_string should have enough buffer to include 2n+2 max size for QUOTENAME(@schema_collection).
DECLARE @sql_string nvarchar(328)
DECLARE @param_definition nvarchar(16)
SET @param_definition = N'@param xml'
SET @sql_string = N'DECLARE @validated_xml XML (DOCUMENT ' + QUOTENAME(@schema_collection, '[') + N'); SELECT @validated_xml = @param';
EXEC @retVal = sp_executesql @sql_string, @param_definition, @param = @parameters
IF (@retVal <> 0)
BEGIN
RETURN (1)
END
END
GO
---------------------------------------------------------------
-- Collection item
---------------------------------------------------------------
IF (OBJECT_ID(N'[dbo].[syscollector_collection_items_internal]', 'U') IS NULL)
BEGIN
PRINT 'Creating table [dbo].[syscollector_collection_items_internal]...'
CREATE TABLE [dbo].[syscollector_collection_items_internal] (
collection_set_id int NOT NULL,
collection_item_id int IDENTITY NOT NULL,
collector_type_uid uniqueidentifier NOT NULL,
name sysname NOT NULL,
name_id int NULL, -- sysmessage id of the name of the item (for localizing system collection set)
frequency int NOT NULL,
parameters xml NULL,
CONSTRAINT [PK_syscollector_collection_items_internal] PRIMARY KEY CLUSTERED (collection_set_id ASC, collection_item_id ASC),
CONSTRAINT [UQ_syscollector_collection_items_internal_name] UNIQUE (name)
)
ALTER TABLE syscollector_collection_items_internal
ADD CONSTRAINT [FK_syscollector_collection_items_internal_syscollector_collection_sets_internal] FOREIGN KEY(collection_set_id)
REFERENCES syscollector_collection_sets_internal (collection_set_id) ON DELETE CASCADE
ALTER TABLE syscollector_collection_items_internal
ADD CONSTRAINT [FK_syscollector_collection_items_internal_syscollector_collector_types_internal] FOREIGN KEY(collector_type_uid)
REFERENCES syscollector_collector_types_internal (collector_type_uid) ON DELETE CASCADE
END ELSE BEGIN
IF (NOT EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name = N'name_id' AND id = OBJECT_ID(N'[dbo].[syscollector_collection_items_internal]')))
BEGIN
PRINT 'Altering table [dbo].[syscollector_collection_items_internal]...'
ALTER TABLE [dbo].[syscollector_collection_items_internal] ADD name_id int NULL
END
END
GO
IF (NOT OBJECT_ID(N'[dbo].[syscollector_collection_items]', 'V') IS NULL)
BEGIN
PRINT 'Dropping view [dbo].[syscollector_collection_items]...'
DROP VIEW [dbo].[syscollector_collection_items]
END
GO
PRINT 'Creating view [dbo].[syscollector_collection_items]...'
GO
CREATE VIEW [dbo].[syscollector_collection_items]
AS
SELECT
i.collection_set_id,
i.collection_item_id,
i.collector_type_uid,
CASE
WHEN i.name_id IS NULL THEN i.name
ELSE FORMATMESSAGE(i.name_id)
END AS name,
i.frequency,
i.parameters
FROM
[dbo].[syscollector_collection_items_internal] i
GO
-- This is a stored procedure of collector_type, but it is created here because it
-- makes references to the collection item view
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_delete_collector_type]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_delete_collector_type]...'
DROP PROCEDURE [dbo].[sp_syscollector_delete_collector_type]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_delete_collector_type]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_delete_collector_type]
@collector_type_uid uniqueidentifier = NULL,
@name sysname = NULL
AS
BEGIN
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_delete_collector_type
ELSE
BEGIN TRANSACTION
BEGIN TRY
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN (1)
END
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collector_type @collector_type_uid OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
IF (EXISTS(SELECT * from dbo.syscollector_collection_items
WHERE @collector_type_uid = collector_type_uid))
BEGIN
RAISERROR(14673, -1, -1, @name)
RETURN (1)
END
DECLARE @schema_collection sysname
-- @sql_string should have enough buffer to include 2n+2 max size for QUOTENAME(@schema_collection).
DECLARE @sql_string nvarchar(285)
SET @schema_collection = (SELECT schema_collection
FROM syscollector_collector_types_internal
WHERE @collector_type_uid = collector_type_uid)
SET @sql_string = N'DROP XML SCHEMA COLLECTION ' + QUOTENAME(@schema_collection, '[');
EXEC sp_executesql @sql_string
DELETE [dbo].[syscollector_collector_types_internal]
WHERE collector_type_uid = @collector_type_uid
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_delete_collector_type
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_verify_collection_item]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_verify_collection_item]...'
DROP PROCEDURE [dbo].[sp_syscollector_verify_collection_item]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_verify_collection_item]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_verify_collection_item]
@collection_item_id int = NULL OUTPUT,
@name sysname = NULL OUTPUT
AS
BEGIN
IF (@name IS NOT NULL)
BEGIN
-- Remove any leading/trailing spaces from parameters
SET @name = NULLIF(LTRIM(RTRIM(@name)), N'')
END
IF (@collection_item_id IS NULL AND @name IS NULL)
BEGIN
RAISERROR(14624, -1, -1, '@collection_item_id, @name')
RETURN(1)
END
IF (@collection_item_id IS NOT NULL AND @name IS NOT NULL)
BEGIN
IF (NOT EXISTS(SELECT *
FROM dbo.syscollector_collection_items
WHERE collection_item_id = @collection_item_id
AND name = @name))
BEGIN
DECLARE @errMsg NVARCHAR(196)
SELECT @errMsg = CONVERT(NVARCHAR(36), @collection_item_id) + ', ' + @name
RAISERROR(14262, -1, -1, '@collection_item_id, @name', @errMsg)
RETURN(1)
END
END
-- Check id
ELSE IF (@collection_item_id IS NOT NULL)
BEGIN
SELECT @name = name
FROM dbo.syscollector_collection_items
WHERE (collection_item_id = @collection_item_id)
-- the view would take care of all the permissions issues.
IF (@name IS NULL)
BEGIN
DECLARE @collection_item_id_as_char VARCHAR(36)
SELECT @collection_item_id_as_char = CONVERT(VARCHAR(36), @collection_item_id)
RAISERROR(14262, -1, -1, '@collection_item_id', @collection_item_id_as_char)
RETURN(1) -- Failure
END
END
-- Check name
ELSE IF (@name IS NOT NULL)
BEGIN
-- get the corresponding collection_item_id (if the collection_item exists)
SELECT @collection_item_id = collection_item_id
FROM dbo.syscollector_collection_items
WHERE (name = @name)
-- the view would take care of all the permissions issues.
IF (@collection_item_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
END
RETURN (0)
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_create_collection_item]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_create_collection_item]...'
DROP PROCEDURE [dbo].[sp_syscollector_create_collection_item]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_create_collection_item]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_create_collection_item]
@collection_set_id int,
@collector_type_uid uniqueidentifier,
@name sysname,
@frequency int = 5, -- set by default to the minimum frequency
@parameters xml = NULL,
@collection_item_id int OUTPUT
AS
BEGIN
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_create_collection_item
ELSE
BEGIN TRANSACTION
BEGIN TRY
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN (1)
END
DECLARE @is_system bit
SELECT @is_system = is_system
FROM dbo.syscollector_collection_sets
WHERE collection_set_id = @collection_set_id
IF (@is_system = 1)
BEGIN
-- cannot update, delete, or add new collection items to a system collection set
RAISERROR(14696, -1, -1);
RETURN (1)
END
SET @name = NULLIF(LTRIM(RTRIM(@name)), N'')
IF (@name IS NULL)
BEGIN
RAISERROR(21263, -1, -1, '@name')
RETURN (1)
END
IF (@frequency < 5)
BEGIN
DECLARE @frequency_as_char VARCHAR(36)
SELECT @frequency_as_char = CONVERT(VARCHAR(36), @frequency)
RAISERROR(21405, 16, -1, @frequency_as_char, '@frequency', 5)
RETURN (1)
END
IF (NOT EXISTS(SELECT * from dbo.syscollector_collector_types
WHERE @collector_type_uid = collector_type_uid))
BEGIN
DECLARE @collector_type_uid_as_char VARCHAR(36)
SELECT @collector_type_uid_as_char = CONVERT(VARCHAR(36), @collector_type_uid)
RAISERROR(14262, -1, -1, '@collector_type_uid', @collector_type_uid_as_char)
RETURN (1)
END
IF (NOT EXISTS(SELECT * from dbo.syscollector_collection_sets
WHERE @collection_set_id = collection_set_id))
BEGIN
DECLARE @collection_set_id_as_char VARCHAR(36)
SELECT @collection_set_id_as_char = CONVERT(VARCHAR(36), @collection_set_id)
RAISERROR(14262, -1, -1, '@collection_set_id', @collection_set_id_as_char)
RETURN (1)
END
DECLARE @is_running bit
SELECT @is_running = is_running
FROM dbo.syscollector_collection_sets
WHERE collection_set_id = @collection_set_id
IF (@is_running = 1)
BEGIN
RAISERROR(14675, -1, -1, @name)
RETURN (1)
END
IF (@parameters IS NULL)
BEGIN
DECLARE @parameter_schema xml
SELECT @parameter_schema = parameter_schema FROM syscollector_collector_types WHERE collector_type_uid = @collector_type_uid
IF (@parameter_schema IS NOT NULL) -- only allows parameters to be null if the collector type has a null schema
BEGIN
RAISERROR(21263, -1, -1, '@parameters')
RETURN (1)
END
END
ELSE IF (LTRIM(RTRIM(CONVERT(nvarchar(max), @parameters))) <> N'') -- don't check if the parameters are empty string
BEGIN
EXEC dbo.sp_syscollector_validate_xml @collector_type_uid = @collector_type_uid, @parameters = @parameters
END
INSERT INTO [dbo].[syscollector_collection_items_internal]
(
collection_set_id,
collector_type_uid,
name,
frequency,
parameters
)
VALUES
(
@collection_set_id,
@collector_type_uid,
@name,
@frequency,
@parameters
)
SET @collection_item_id = SCOPE_IDENTITY()
IF (@collection_item_id IS NULL)
BEGIN
DECLARE @collection_item_id_as_char VARCHAR(36)
SELECT @collection_item_id_as_char = CONVERT(VARCHAR(36), @collection_item_id)
RAISERROR(14262, -1, -1, '@collection_item_id', @collection_item_id_as_char)
RETURN (1)
END
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_create_collection_item
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_update_collection_item_internal]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_update_collection_item_internal]...'
DROP PROCEDURE [dbo].[sp_syscollector_update_collection_item_internal]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_update_collection_item_internal]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_update_collection_item_internal]
@collection_item_id int = NULL,
@name sysname = NULL,
@new_name sysname = NULL,
@frequency int = NULL,
@parameters xml = NULL
AS
BEGIN
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_update_collection_item
ELSE
BEGIN TRANSACTION
BEGIN TRY
UPDATE [dbo].[syscollector_collection_items_internal]
SET
name = ISNULL(@new_name, name),
frequency = ISNULL(@frequency, frequency),
parameters = ISNULL(@parameters, parameters)
WHERE @collection_item_id = collection_item_id
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_update_collection_item
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_update_collection_item]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_update_collection_item]...'
DROP PROCEDURE [dbo].[sp_syscollector_update_collection_item]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_update_collection_item]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_update_collection_item]
@collection_item_id int = NULL,
@name sysname = NULL,
@new_name sysname = NULL,
@frequency int = NULL,
@parameters xml = NULL
AS
BEGIN
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_operator')
RETURN(1) -- Failure
END
-- Security checks (restrict functionality for non-dc_admin-s)
IF ((NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
AND (@new_name IS NOT NULL))
BEGIN
RAISERROR(14676, -1, -1, '@new_name', 'dc_admin')
RETURN (1) -- Failure
END
IF ((NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
AND (@parameters IS NOT NULL))
BEGIN
RAISERROR(14676, -1, -1, '@parameters', 'dc_admin')
RETURN (1) -- Failure
END
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collection_item @collection_item_id OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (@retVal)
IF (@frequency < 5)
BEGIN
DECLARE @frequency_as_char VARCHAR(36)
SELECT @frequency_as_char = CONVERT(VARCHAR(36), @frequency)
RAISERROR(21405, 16, -1, @frequency_as_char, '@frequency', 5)
RETURN (1)
END
IF (LEN(@new_name) = 0) -- can't rename to an empty string
BEGIN
RAISERROR(21263, -1, -1, '@new_name')
RETURN(1) -- Failure
END
-- Remove any leading/trailing spaces from parameters
SET @new_name = LTRIM(RTRIM(@new_name))
DECLARE @collection_set_name sysname
DECLARE @is_system bit
DECLARE @is_running bit
DECLARE @collector_type_uid uniqueidentifier
DECLARE @collection_set_id int
SELECT @is_running = s.is_running,
@is_system = s.is_system,
@collection_set_name = s.name,
@collector_type_uid = i.collector_type_uid,
@collection_set_id = s.collection_set_id
FROM dbo.syscollector_collection_sets s,
dbo.syscollector_collection_items i
WHERE s.collection_set_id = i.collection_set_id
AND i.collection_item_id = @collection_item_id
IF (@is_system = 1 AND (@new_name IS NOT NULL OR @parameters IS NOT NULL))
BEGIN
-- cannot update, delete, or add new collection items to a system collection set
RAISERROR(14696, -1, -1);
RETURN (1)
END
IF (@parameters IS NOT NULL)
BEGIN
EXEC @retVal = dbo.sp_syscollector_validate_xml @collector_type_uid = @collector_type_uid, @parameters = @parameters
IF (@retVal <> 0)
RETURN (@retVal)
END
-- if the collection item is running, stop it before update
IF (@is_running = 1)
BEGIN
EXEC @retVal = sp_syscollector_stop_collection_set @collection_set_id = @collection_set_id
IF (@retVal <> 0)
RETURN(1)
END
-- all conditions go, perform the update
EXEC @retVal = sp_syscollector_update_collection_item_internal
@collection_item_id = @collection_item_id,
@name = @name,
@new_name = @new_name,
@frequency = @frequency,
@parameters = @parameters
-- if you stopped the collection set, restart it
IF (@is_running = 1)
BEGIN
EXEC @retVal = sp_syscollector_start_collection_set @collection_set_id = @collection_set_id
IF (@retVal <> 0)
RETURN (1)
END
RETURN (0)
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_delete_collection_item_internal]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_delete_collection_item_internal]...'
DROP PROCEDURE [dbo].[sp_syscollector_delete_collection_item_internal]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_delete_collection_item_internal]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_delete_collection_item_internal]
@collection_item_id int,
@name sysname
AS
BEGIN
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_delete_collection_item
ELSE
BEGIN TRANSACTION
BEGIN TRY
DELETE [dbo].[syscollector_collection_items_internal]
WHERE collection_item_id = @collection_item_id
AND name = @name
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_delete_collection_item
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_delete_collection_item]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_delete_collection_item]...'
DROP PROCEDURE [dbo].[sp_syscollector_delete_collection_item]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_delete_collection_item]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_delete_collection_item]
@collection_item_id int = NULL,
@name sysname = NULL
AS
BEGIN
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN(1) -- Failure
END
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collection_item @collection_item_id OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
DECLARE @is_system bit
DECLARE @is_running bit
DECLARE @collection_set_id int
SELECT @is_running = s.is_running,
@is_system = s.is_system,
@collection_set_id = s.collection_set_id
FROM dbo.syscollector_collection_sets s,
dbo.syscollector_collection_items i
WHERE i.collection_item_id = @collection_item_id
AND s.collection_set_id = i.collection_set_id
IF (@is_system = 1)
BEGIN
-- cannot update, delete, or add new collection items to a system collection set
RAISERROR(14696, -1, -1);
RETURN(1)
END
IF (@is_running = 1)
BEGIN
-- stop the collection set if it was running
EXEC @retVal = sp_syscollector_stop_collection_set @collection_set_id = @collection_set_id
IF (@retVal <> 0)
RETURN (1)
END
-- all checks go, perform delete
EXEC @retVal = sp_syscollector_delete_collection_item_internal @collection_item_id = @collection_item_id, @name = @name
IF (@retVal <> 0)
RETURN (1)
RETURN (0)
END
GO
---------------------------------------------------------------
-- Collection Set runtime procedures
---------------------------------------------------------------
IF (NOT OBJECT_ID('dbo.sp_syscollector_start_collection_set', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_start_collection_set]...'
DROP PROCEDURE [dbo].[sp_syscollector_start_collection_set]
END
GO
PRINT ''
PRINT 'Creating procedure [dbo].[sp_syscollector_start_collection_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_start_collection_set]
@collection_set_id int = NULL,
@name sysname = NULL
WITH EXECUTE AS OWNER -- 'MS_DataCollectorInternalUser'
AS
BEGIN
SET NOCOUNT ON
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_start_collection_set
ELSE
BEGIN TRANSACTION
BEGIN TRY
-- Security check (role membership)
EXECUTE AS CALLER;
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
REVERT;
RAISERROR(14677, -1, -1, 'dc_operator')
RETURN(1) -- Failure
END
REVERT;
-- check if SQL Server Agent is enabled
DECLARE @agent_enabled int
SELECT @agent_enabled = CAST(value_in_use AS int) FROM sys.configurations WHERE name = N'Agent XPs'
IF @agent_enabled <> 1
BEGIN
RAISERROR(14688, -1, -1)
RETURN (1)
END
-- check if MDW is setup
DECLARE @instance_name sysname
SELECT @instance_name = CONVERT(sysname,parameter_value)
FROM [msdb].[dbo].[syscollector_config_store_internal]
WHERE parameter_name = N'MDWInstance'
IF (@instance_name IS NULL)
BEGIN
RAISERROR(14689, -1, -1)
RETURN (1)
END
DECLARE @database_name sysname
SELECT @database_name = CONVERT(sysname,parameter_value)
FROM [msdb].[dbo].[syscollector_config_store_internal]
WHERE parameter_name = N'MDWDatabase'
IF (@database_name IS NULL)
BEGIN
RAISERROR(14689, -1, -1)
RETURN (1)
END
-- Verify the input parameters
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collection_set @collection_set_id OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
-- Check if the collection set does not have any collection items
IF NOT EXISTS(
SELECT i.collection_item_id
FROM [dbo].[syscollector_collection_sets] AS s
INNER JOIN [dbo].[syscollector_collection_items] AS i
ON(s.collection_set_id = i.collection_set_id)
WHERE s.collection_set_id = @collection_set_id
)
BEGIN
RAISERROR(14685, 10, -1, @name) -- Raise a warning message
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END
DECLARE @proxy_id int;
DECLARE @collection_job_id uniqueidentifier
DECLARE @upload_job_id uniqueidentifier
DECLARE @schedule_uid uniqueidentifier;
SELECT
@collection_job_id = collection_job_id,
@upload_job_id = upload_job_id,
@proxy_id = proxy_id,
@schedule_uid = schedule_uid
FROM [dbo].[syscollector_collection_sets_internal]
WHERE collection_set_id = @collection_set_id;
-- Check if the set does not have a proxy
IF (@proxy_id IS NULL)
BEGIN
-- to start a collection set without a proxy, the caller has to be a sysadmin
EXECUTE AS CALLER;
IF (NOT (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1))
BEGIN
REVERT;
RAISERROR(14692, -1, -1, @name)
RETURN (1)
END
REVERT;
END
-- Starting a collection set requires a schedule
IF @schedule_uid IS NULL
BEGIN
RAISERROR(14693, -1, -1)
RETURN (1)
END
-- Check if we have jobs created, and if not, create them
IF (@collection_job_id IS NULL AND @upload_job_id IS NULL)
BEGIN
-- Jobs not created yet, go and crete them
-- We need to get some data from collection_sets table
-- before we do that.
DECLARE @collection_set_uid uniqueidentifier;
DECLARE @schedule_id int;
DECLARE @collection_mode int;
SELECT
@collection_set_uid = collection_set_uid,
@collection_mode = collection_mode
FROM
[dbo].[syscollector_collection_sets_internal]
WHERE
collection_set_id = @collection_set_id;
-- Sanity check
-- Make sure the proxy and schedule are still there, someone could have
-- remove them between when the collection set was created and now.
IF (@proxy_id IS NOT NULL)
BEGIN
DECLARE @proxy_name sysname
-- this will throw if the id does not exist
EXEC @retVal = sp_verify_proxy_identifiers '@proxy_name', '@proxy_id', @proxy_name OUTPUT, @proxy_id OUTPUT
IF (@retVal <> 0)
RETURN (1)
END
SELECT @schedule_id = schedule_id FROM sysschedules_localserver_view WHERE @schedule_uid = schedule_uid
EXEC @retVal = sp_verify_schedule_identifiers @name_of_name_parameter = '@schedule_name',
@name_of_id_parameter = '@schedule_id',
@schedule_name = NULL,
@schedule_id = @schedule_id,
@owner_sid = NULL,
@orig_server_id = NULL
IF (@retVal <> 0)
RETURN (1)
-- Go add the jobs
EXEC [dbo].[sp_syscollector_create_jobs]
@collection_set_id = @collection_set_id,
@collection_set_uid = @collection_set_uid,
@collection_set_name = @name,
@proxy_id = @proxy_id,
@schedule_id = @schedule_id,
@collection_mode = @collection_mode,
@collection_job_id = @collection_job_id OUTPUT,
@upload_job_id = @upload_job_id OUTPUT
-- Finally, update the collection_sets table
UPDATE [dbo].[syscollector_collection_sets_internal]
SET
upload_job_id = @upload_job_id,
collection_job_id = @collection_job_id
WHERE @collection_set_id = collection_set_id
END
-- Update the is_running column for this collection set
-- There is a trigger defined for that table that turns on
-- the collection and upload jobs in response to that bit
-- changing.
UPDATE [dbo].[syscollector_collection_sets_internal]
SET is_running = 1
WHERE collection_set_id = @collection_set_id
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_start_collection_set
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('dbo.sp_syscollector_stop_collection_set', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_stop_collection_set]...'
DROP PROCEDURE [dbo].[sp_syscollector_stop_collection_set]
END
GO
PRINT ''
PRINT 'Creating procedure [dbo].[sp_syscollector_stop_collection_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_stop_collection_set]
@collection_set_id int = NULL,
@name sysname = NULL,
@stop_collection_job bit = 1 -- Do we need to stop the collection job, YES by default
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_operator')
RETURN(1) -- Failure
END
-- Verify the input parameters
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collection_set @collection_set_id OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
IF (@stop_collection_job = 1)
BEGIN
DECLARE @collection_mode INT
DECLARE @collection_job_id UNIQUEIDENTIFIER
SELECT @collection_mode = collection_mode, @collection_job_id = collection_job_id
FROM dbo.syscollector_collection_sets
WHERE collection_set_id = @collection_set_id
DECLARE @is_collection_job_running INT
EXECUTE [dbo].[sp_syscollector_get_collection_set_execution_status]
@collection_set_id = @collection_set_id,
@is_collection_running = @is_collection_job_running OUTPUT
-- Stop the collection job if we are in cached mode, this should signal the runtime to exit
IF (@is_collection_job_running = 1 -- Collection job is running
AND @collection_mode = 0
AND @stop_collection_job = 1)
BEGIN
EXEC sp_stop_job @job_id = @collection_job_id
END
END
-- Update the is_running column for this collection set
-- There is a trigger defined for that table that turns off
-- the collection and uplaod jobs in response to that bit
-- changing.
UPDATE [dbo].[syscollector_collection_sets_internal]
SET is_running = 0
WHERE collection_set_id = @collection_set_id
RETURN (0)
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_get_collection_set_execution_status]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_get_collection_set_execution_status]...'
DROP PROCEDURE [dbo].[sp_syscollector_get_collection_set_execution_status]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_get_collection_set_execution_status]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_get_collection_set_execution_status]
@collection_set_id int,
@is_running int = NULL OUTPUT,
@is_collection_running int = NULL OUTPUT,
@collection_job_state int = NULL OUTPUT,
@is_upload_running int = NULL OUTPUT,
@upload_job_state int = NULL OUTPUT
WITH EXECUTE AS OWNER -- 'MS_DataCollectorInternalUser'
AS
BEGIN
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_get_execution_status
ELSE
BEGIN TRANSACTION
BEGIN TRY
DECLARE @xp_results TABLE (job_id UNIQUEIDENTIFIER NOT NULL,
last_run_date INT NOT NULL,
last_run_time INT NOT NULL,
next_run_date INT NOT NULL,
next_run_time INT NOT NULL,
next_run_schedule_id INT NOT NULL,
requested_to_run INT NOT NULL, -- BOOL
request_source INT NOT NULL,
request_source_id sysname COLLATE database_default NULL,
running INT NOT NULL, -- BOOL
current_step INT NOT NULL,
current_retry_attempt INT NOT NULL,
job_state INT NOT NULL)
DECLARE @is_sysadmin INT
SELECT @is_sysadmin = ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0)
DECLARE @collection_job_id UNIQUEIDENTIFIER
DECLARE @upload_job_id UNIQUEIDENTIFIER
SELECT @collection_job_id = collection_job_id, @upload_job_id = upload_job_id
FROM dbo.syscollector_collection_sets WHERE collection_set_id = @collection_set_id
DECLARE @agent_enabled int
SELECT @agent_enabled = CAST(value_in_use AS int) FROM sys.configurations WHERE name = N'Agent XPs'
-- initialize to 0 == not running state; when agent XPs are disabled, call to xp_sqlagent_enum_jobs is never made in
-- code below. When Agent Xps are disabled agent would not be running, in this case, jobs will also be in 'not running" state
SET @is_collection_running = 0
SET @is_upload_running = 0
SET @collection_job_state = 0
SET @upload_job_state = 0
IF (@agent_enabled <> 0)
BEGIN
INSERT INTO @xp_results
EXECUTE master.dbo.xp_sqlagent_enum_jobs @is_sysadmin, N'', @upload_job_id
INSERT INTO @xp_results
EXECUTE master.dbo.xp_sqlagent_enum_jobs @is_sysadmin, N'', @collection_job_id
SELECT @is_collection_running = running,
@collection_job_state = job_state
FROM @xp_results WHERE job_id = @collection_job_id
SELECT @is_upload_running = running,
@upload_job_state = job_state
FROM @xp_results WHERE job_id = @upload_job_id
END
SELECT @is_running = is_running FROM dbo.syscollector_collection_sets WHERE collection_set_id = @collection_set_id
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_get_execution_status
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
IF (NOT OBJECT_ID('dbo.sp_syscollector_upload_collection_set', 'P') IS NULL)
BEGIN
DROP PROCEDURE [dbo].[sp_syscollector_upload_collection_set]
END
GO
PRINT ''
PRINT 'Creating procedure [dbo].[sp_syscollector_upload_collection_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_upload_collection_set]
@collection_set_id int = NULL,
@name sysname = NULL
WITH EXECUTE AS OWNER -- 'MS_DataCollectorInternalUser'
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
EXECUTE AS CALLER;
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
REVERT;
RAISERROR(14677, -1, -1, 'dc_operator')
RETURN(1) -- Failure
END
REVERT;
-- Verify the input parameters
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collection_set @collection_set_id OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
-- Make sure the collection set is running and is in the right mode
DECLARE @is_running bit
DECLARE @collection_mode smallint
SELECT
@is_running = is_running,
@collection_mode = collection_mode
FROM [dbo].[syscollector_collection_sets]
WHERE collection_set_id = @collection_set_id
IF (@collection_mode <> 0)
BEGIN
RAISERROR(14694, -1, -1, @name)
RETURN(1)
END
IF (@is_running = 0)
BEGIN
RAISERROR(14674, -1, -1, @name)
RETURN(1)
END
-- Make sure the collector is enabled
EXEC @retVal = [dbo].[sp_syscollector_verify_collector_state] @desired_state = 1
IF (@retVal <> 0)
RETURN (1)
-- Check if the upload job is currently running
DECLARE @is_upload_job_running INT
EXECUTE [dbo].[sp_syscollector_get_collection_set_execution_status]
@collection_set_id = @collection_set_id,
@is_upload_running = @is_upload_job_running OUTPUT
IF (@is_upload_job_running = 0)
BEGIN
-- Job is not running, we can trigger it now
DECLARE @job_id UNIQUEIDENTIFIER
SELECT @job_id = upload_job_id
FROM [dbo].[syscollector_collection_sets]
WHERE collection_set_id = @collection_set_id
EXEC @retVal = sp_start_job @job_id = @job_id
IF (@retVal <> 0)
RETURN (1)
END
RETURN (0)
END
GO
IF (NOT OBJECT_ID('dbo.sp_syscollector_run_collection_set', 'P') IS NULL)
BEGIN
DROP PROCEDURE [dbo].[sp_syscollector_run_collection_set]
END
GO
PRINT ''
PRINT 'Creating procedure [dbo].[sp_syscollector_run_collection_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_run_collection_set]
@collection_set_id int = NULL,
@name sysname = NULL
WITH EXECUTE AS OWNER -- 'MS_DataCollectorInternalUser'
AS
BEGIN
SET NOCOUNT ON
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_run_collection_set
ELSE
BEGIN TRANSACTION
BEGIN TRY
-- Security check (role membership)
EXECUTE AS CALLER;
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
REVERT;
RAISERROR(14677, -1, -1, 'dc_operator')
RETURN(1) -- Failure
END
REVERT;
-- Verify the input parameters
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collection_set @collection_set_id OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
-- Make sure the collection set is in the right mode
DECLARE @collection_mode smallint
DECLARE @collection_set_uid uniqueidentifier;
SELECT
@collection_set_uid = collection_set_uid,
@collection_mode = collection_mode
FROM [dbo].[syscollector_collection_sets]
WHERE collection_set_id = @collection_set_id
IF (@collection_mode <> 1)
BEGIN
RAISERROR(14695, -1, -1, @name)
RETURN(1)
END
-- Make sure the collector is enabled
EXEC @retVal = [dbo].[sp_syscollector_verify_collector_state] @desired_state = 1
IF (@retVal <> 0)
RETURN (1)
-- check if SQL Server Agent is enabled
DECLARE @agent_enabled int
SELECT @agent_enabled = CAST(value_in_use AS int) FROM sys.configurations WHERE name = N'Agent XPs'
IF @agent_enabled <> 1
BEGIN
RAISERROR(14688, -1, -1)
RETURN (1)
END
-- check if MDW is setup
DECLARE @instance_name sysname
SELECT @instance_name = CONVERT(sysname,parameter_value)
FROM [msdb].[dbo].[syscollector_config_store_internal]
WHERE parameter_name = N'MDWInstance'
IF (@instance_name IS NULL)
BEGIN
RAISERROR(14689, -1, -1)
RETURN (1)
END
DECLARE @database_name sysname
SELECT @database_name = CONVERT(sysname,parameter_value)
FROM [msdb].[dbo].[syscollector_config_store_internal]
WHERE parameter_name = N'MDWDatabase'
IF (@database_name IS NULL)
BEGIN
RAISERROR(14689, -1, -1)
RETURN (1)
END
-- Make sure the jobs are created for the collection set
-- Verify the input parameters
EXEC @retVal = dbo.sp_syscollector_verify_collection_set @collection_set_id OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
-- Check if the collection set does not have any collection items
IF NOT EXISTS(
SELECT i.collection_item_id
FROM [dbo].[syscollector_collection_sets] AS s
INNER JOIN [dbo].[syscollector_collection_items] AS i
ON(s.collection_set_id = i.collection_set_id)
WHERE s.collection_set_id = @collection_set_id
)
BEGIN
RAISERROR(14685, 10, -1, @name) -- Raise a warning message
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END
DECLARE @proxy_id int;
DECLARE @collection_job_id uniqueidentifier
DECLARE @upload_job_id uniqueidentifier
SELECT @collection_job_id = collection_job_id,
@upload_job_id = upload_job_id,
@proxy_id = proxy_id
FROM [dbo].[syscollector_collection_sets_internal]
WHERE collection_set_id = @collection_set_id;
-- Check if the set does not have a proxy
IF (@proxy_id IS NULL)
BEGIN
-- to start a collection set without a proxy, the caller has to be a sysadmin
EXECUTE AS CALLER;
IF (NOT (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 1))
BEGIN
REVERT;
RAISERROR(14692, -1, -1, @name)
RETURN (1)
END
REVERT;
END
-- Check if we have jobs created, and if not, create them
DECLARE @jobs_just_created bit
SET @jobs_just_created = 0 -- False until further notice
IF (@collection_job_id IS NULL AND @upload_job_id IS NULL)
BEGIN
DECLARE @schedule_id int;
DECLARE @schedule_uid uniqueidentifier;
SELECT
@schedule_uid = schedule_uid
FROM [dbo].[syscollector_collection_sets_internal]
WHERE collection_set_id = @collection_set_id;
IF (@schedule_uid IS NOT NULL)
BEGIN
SELECT @schedule_id = schedule_id FROM sysschedules_localserver_view WHERE @schedule_uid = schedule_uid
END
-- Sanity check
-- Make sure the proxy and schedule are still there, someone could have
-- remove them between when the collection set was created and now.
IF (@proxy_id IS NOT NULL)
BEGIN
DECLARE @proxy_name sysname
-- this will throw an error of proxy_id does not exist
EXEC @retVal = msdb.dbo.sp_verify_proxy_identifiers '@proxy_name', '@proxy_id', @proxy_name OUTPUT, @proxy_id OUTPUT
IF (@retVal <> 0)
RETURN (0)
END
IF (@schedule_uid IS NOT NULL)
BEGIN
EXEC @retVal = sp_verify_schedule_identifiers @name_of_name_parameter = '@schedule_name',
@name_of_id_parameter = '@schedule_id',
@schedule_name = NULL,
@schedule_id = @schedule_id,
@owner_sid = NULL,
@orig_server_id = NULL
IF (@retVal <> 0)
RETURN (1)
END
-- Go add the jobs
EXEC [dbo].[sp_syscollector_create_jobs]
@collection_set_id = @collection_set_id,
@collection_set_uid = @collection_set_uid,
@collection_set_name = @name,
@proxy_id = @proxy_id,
@schedule_id = @schedule_id,
@collection_mode = @collection_mode,
@collection_job_id = @collection_job_id OUTPUT,
@upload_job_id = @upload_job_id OUTPUT
-- Finally, update the collection_sets table
UPDATE [dbo].[syscollector_collection_sets_internal]
SET
upload_job_id = @upload_job_id,
collection_job_id = @collection_job_id
WHERE @collection_set_id = collection_set_id
SET @jobs_just_created = 1 -- Record the fact that we have just created the job here
END
IF (@jobs_just_created = 1)
BEGIN -- We created the jobs here in this transaction, post a request for agent to start as soon as we commit
EXEC @retVal = sp_start_job @job_id = @upload_job_id
IF (@retVal <> 0)
RETURN (1)
END
ELSE
BEGIN
-- The jobs were created previously, we need to guard against it already executing by the schedule
-- So, check if the job is currently running before asking agent to start it
DECLARE @is_upload_job_running INT
EXECUTE [dbo].[sp_syscollector_get_collection_set_execution_status]
@collection_set_id = @collection_set_id,
@is_upload_running = @is_upload_job_running OUTPUT
IF (@is_upload_job_running = 0)
BEGIN
-- Job is not running, we can trigger it now
-- We run only one job because for this (non-cached) mode there is only one job. The same id is stored
-- as collection and upload job id
EXEC @retVal = sp_start_job @job_id = @upload_job_id
IF (@retVal <> 0)
RETURN (1)
END
END
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_run_collection_set
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
PRINT 'Creating trigger [dbo].[syscollector_collection_set_is_running_update_trigger] on [dbo].[syscollector_collection_sets_internal]'
GO
IF NOT OBJECT_ID('dbo.syscollector_collection_set_is_running_update_trigger', 'TR') IS NULL
DROP TRIGGER [dbo].[syscollector_collection_set_is_running_update_trigger]
GO
CREATE TRIGGER [dbo].[syscollector_collection_set_is_running_update_trigger] on [dbo].[syscollector_collection_sets_internal]
WITH EXECUTE AS OWNER -- 'MS_DataCollectorInternalUser'
FOR UPDATE
AS
BEGIN
DECLARE @collection_set_id INT
DECLARE @is_running BIT
DECLARE @old_is_running BIT
DECLARE @collection_mode SMALLINT
IF (NOT UPDATE (is_running))
RETURN
DECLARE @collector_enabled int
SET @collector_enabled = CONVERT(int, (SELECT parameter_value FROM dbo.syscollector_config_store_internal
WHERE parameter_name = 'CollectorEnabled'))
IF @collector_enabled = 0
BEGIN
-- flipping the is_running bit has no effect when the collector is disabled
RAISERROR(14682, 10, -1) -- severity 10 emits a warning
END
ELSE
BEGIN
DECLARE inserted_cursor CURSOR LOCAL FOR
SELECT collection_set_id, is_running, collection_mode
FROM inserted
OPEN inserted_cursor
FETCH inserted_cursor INTO @collection_set_id, @is_running, @collection_mode
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @old_is_running = is_running FROM deleted WHERE collection_set_id = @collection_set_id
-- If there is a change in the state, handle accordingly
IF (@old_is_running <> @is_running)
BEGIN
IF (@is_running = 0)
BEGIN
EXEC dbo.sp_syscollector_stop_collection_set_jobs @collection_set_id = @collection_set_id
END
ELSE IF (@is_running = 1)
BEGIN
EXEC dbo.sp_syscollector_start_collection_set_jobs @collection_set_id = @collection_set_id
END
END
FETCH inserted_cursor INTO @collection_set_id, @is_running, @collection_mode
END
CLOSE inserted_cursor
DEALLOCATE inserted_cursor
END
END
GO
PRINT ''
PRINT 'Creating stored procedure syscollector_stop_collection_set_jobs...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_stop_collection_set_jobs', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_stop_collection_set_jobs]
GO
CREATE PROCEDURE [dbo].[sp_syscollector_stop_collection_set_jobs]
@collection_set_id int
AS
BEGIN
SET NOCOUNT ON
-- Collection set stopped. Make sure the following happens:
-- 1. Detach upload schedule
-- 2. Collection job is stopped
-- 3. Upload job is kicked once if it is not running now
-- 4. Collection and upload jobs are disabled
-- 5. Attach upload schedule
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_stop_collection_set_jobs
ELSE
BEGIN TRANSACTION
BEGIN TRY
DECLARE @collection_job_id uniqueidentifier
DECLARE @upload_job_id uniqueidentifier
DECLARE @schedule_uid uniqueidentifier
DECLARE @collection_mode smallint
SELECT @collection_job_id = collection_job_id,
@upload_job_id = upload_job_id,
@collection_mode = collection_mode,
@schedule_uid = schedule_uid
FROM dbo.syscollector_collection_sets
WHERE collection_set_id = @collection_set_id
DECLARE @schedule_id int
IF (@collection_mode != 1) -- detach schedule for continuous and snapshot modes
BEGIN
SELECT @schedule_id = schedule_id from sysschedules_localserver_view WHERE @schedule_uid = schedule_uid
IF (@schedule_id IS NULL)
BEGIN
DECLARE @schedule_uid_as_char VARCHAR(36)
SELECT @schedule_uid_as_char = CONVERT(VARCHAR(36), @schedule_uid)
RAISERROR(14262, -1, -1, '@schedule_uid', @schedule_uid_as_char)
RETURN (1)
END
-- Detach schedule
EXEC dbo.sp_detach_schedule
@job_id = @upload_job_id,
@schedule_id = @schedule_id,
@delete_unused_schedule = 0 -- do not delete schedule, might need to attach it back again
END
DECLARE @is_upload_job_running INT
EXECUTE [dbo].[sp_syscollector_get_collection_set_execution_status]
@collection_set_id = @collection_set_id,
@is_upload_running = @is_upload_job_running OUTPUT
-- Upload job (needs to be kicked off for continuous collection mode)
IF (@is_upload_job_running = 0 -- If the upload job is not already in progress
AND @collection_mode = 0) -- don't do it for adhoc or snapshot, they will handle it on their own
BEGIN
EXEC sp_start_job @job_id = @upload_job_id, @error_flag = 0
END
-- Disable both jobs
EXEC sp_update_job @job_id = @collection_job_id, @enabled = 0
EXEC sp_update_job @job_id = @upload_job_id, @enabled = 0
IF (@collection_mode != 1) -- attach schedule for continuous and snapshot modes
BEGIN
-- Attach schedule
EXEC dbo.sp_attach_schedule
@job_id = @upload_job_id,
@schedule_id = @schedule_id
END
-- Log the stop of the collection set
EXEC sp_syscollector_event_oncollectionstop @collection_set_id = @collection_set_id
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_stop_collection_set_jobs
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
PRINT ''
PRINT 'Creating stored procedure syscollector_start_collection_set_jobs...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_start_collection_set_jobs', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_start_collection_set_jobs]
GO
CREATE PROCEDURE [dbo].[sp_syscollector_start_collection_set_jobs]
@collection_set_id int
AS
BEGIN
SET NOCOUNT ON
-- Collection set started. Make sure the following happens:
-- 1. Collection and upload jobs are enabled
-- 2. Collection job is started if it is defined as running continously
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_start_collection_set_jobs
ELSE
BEGIN TRANSACTION
BEGIN TRY
-- Log the start of the collection set
DECLARE @log_id bigint
EXEC sp_syscollector_event_oncollectionstart @collection_set_id = @collection_set_id, @log_id = @log_id OUTPUT
-- Enable both jobs
DECLARE @collection_job_id uniqueidentifier
DECLARE @upload_job_id uniqueidentifier
DECLARE @collection_mode smallint
SELECT @collection_job_id = collection_job_id,
@upload_job_id = upload_job_id,
@collection_mode = collection_mode
FROM dbo.syscollector_collection_sets
WHERE collection_set_id = @collection_set_id
EXEC sp_update_job @job_id = @collection_job_id, @enabled = 1
EXEC sp_update_job @job_id = @upload_job_id, @enabled = 1
-- Start the collection job if you are in ad hoc or continuous modes
IF (@collection_mode = 1 OR @collection_mode = 0)
BEGIN
EXEC sp_start_job @job_id = @collection_job_id, @error_flag = 0
END
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_start_collection_set_jobs
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
---------------------------------------------------------------
-- Collection Set execution log
---------------------------------------------------------------
IF (OBJECT_ID('dbo.syscollector_execution_log_internal', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table syscollector_execution_log_internal...'
CREATE TABLE [dbo].[syscollector_execution_log_internal]
(
log_id bigint IDENTITY(1,1) NOT NULL, -- Unique log entry id. Each execution log gets a new one
parent_log_id bigint NULL, -- Id of the parent execution context. NULL for the root node.
collection_set_id int NOT NULL, -- Id of the collection set that owns this entry
collection_item_id int NULL, -- Collection item id
start_time datetime NOT NULL, -- Collection set or package execution start time
last_iteration_time datetime NULL, -- For continously running packages, last time an interation has been started
finish_time datetime NULL, -- Collection set or package execution end time
runtime_execution_mode smallint NULL, -- 0 - Collection, 1 - Upload
status smallint NOT NULL, -- 0 - Running, 1 - Finished, 2 - Error, 3 - Warning
operator nvarchar(128) NOT NULL, -- Name of the user running the collection set or package
package_id uniqueidentifier NULL, -- Id of a package, NULL for collection sets
package_execution_id uniqueidentifier NULL, -- Execution Id generated by SSIS for each package execution. Use to join events from sysssislog. NULL for collection sets
failure_message nvarchar(2048) NULL -- Message that indicates package failure. NULL if no failure
CONSTRAINT [PK_syscollector_execution_log] PRIMARY KEY CLUSTERED (log_id ASC),
CONSTRAINT [FK_syscollector_execution_log_collection_set_id] FOREIGN KEY (collection_set_id)
REFERENCES [dbo].[syscollector_collection_sets_internal] (collection_set_id),
)
END
go
PRINT ''
PRINT 'Creating view syscollector_execution_log...'
IF (NOT OBJECT_ID('dbo.syscollector_execution_log', 'V') IS NULL)
DROP VIEW [dbo].[syscollector_execution_log]
go
CREATE VIEW [dbo].[syscollector_execution_log] AS
SELECT
log_id,
ISNULL(parent_log_id, 0) as parent_log_id,
collection_set_id,
collection_item_id,
start_time,
last_iteration_time,
finish_time,
runtime_execution_mode,
[status],
operator,
package_id,
msdb.dbo.fn_syscollector_get_package_path(package_id) as package_name,
package_execution_id,
failure_message
FROM dbo.syscollector_execution_log_internal;
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_delete_jobs]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_delete_jobs]...'
DROP PROCEDURE [dbo].[sp_syscollector_delete_jobs]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_delete_jobs]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_delete_jobs]
@collection_job_id uniqueidentifier,
@upload_job_id uniqueidentifier,
@schedule_id int = NULL,
@collection_mode smallint
AS
BEGIN
-- delete the jobs corresponding to the collection set
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_syscollector_delete_jobs
ELSE
BEGIN TRANSACTION
BEGIN TRY
IF (@collection_mode = 1) -- non-cached mode
BEGIN
IF (@upload_job_id IS NOT NULL)
BEGIN
-- note, upload job id = collection job id in this mode
IF (@schedule_id IS NOT NULL)
BEGIN
EXEC dbo.sp_detach_schedule
@job_id = @upload_job_id,
@schedule_id = @schedule_id,
@delete_unused_schedule = 0
END
EXEC dbo.sp_delete_jobserver
@job_id = @upload_job_id,
@server_name = N'(local)'
EXEC dbo.sp_delete_job
@job_id = @upload_job_id
END
END
ELSE -- cached mode
BEGIN
-- detach schedules, delete job servers, then delete jobs
IF (@upload_job_id IS NOT NULL)
BEGIN
EXEC dbo.sp_detach_schedule
@job_id = @upload_job_id,
@schedule_id = @schedule_id,
@delete_unused_schedule = 0
EXEC dbo.sp_delete_jobserver
@job_id = @upload_job_id,
@server_name = N'(local)'
EXEC dbo.sp_delete_job
@job_id = @upload_job_id
END
IF (@collection_job_id IS NOT NULL)
BEGIN
EXEC dbo.sp_detach_schedule
@job_id = @collection_job_id,
@schedule_name = N'RunAsSQLAgentServiceStartSchedule',
@delete_unused_schedule = 0
EXEC dbo.sp_delete_jobserver
@job_id = @collection_job_id,
@server_name = N'(local)'
EXEC dbo.sp_delete_job
@job_id = @collection_job_id
END
END
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_syscollector_delete_jobs
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
---------------------------------------------------------------
-- Collection Set execution stats
---------------------------------------------------------------
IF (OBJECT_ID('dbo.syscollector_execution_stats_internal', 'U') IS NULL)
BEGIN
PRINT ''
PRINT 'Creating table syscollector_execution_stats_internal...'
CREATE TABLE [dbo].[syscollector_execution_stats_internal]
(
log_id bigint NOT NULL, -- Log_id of the package that inserts the row
task_name nvarchar(128) NOT NULL, -- Name of the task/component in the package that reports the execution stats
execution_row_count_in int NULL, -- Number of rows that entered the data flow from its source transformations
execution_row_count_out int NULL, -- Number of rows that exited the data flow into its destination transformations
execution_row_count_errors int NULL, -- Number of rows that were re-directed to an error output due to processing errors
execution_time_ms int NULL, -- Execution time of the data flow
log_time datetime NOT NULL -- Date and time when this entry was logged
CONSTRAINT [PK_syscollector_execution_stats] PRIMARY KEY CLUSTERED (log_id ASC, task_name ASC, log_time DESC),
CONSTRAINT [FK_syscollector_execution_stats_log_id] FOREIGN KEY (log_id) REFERENCES [dbo].[syscollector_execution_log_internal] (log_id) ON DELETE CASCADE
)
END
go
PRINT ''
PRINT 'Creating view syscollector_execution_stats...'
IF (NOT OBJECT_ID('dbo.syscollector_execution_stats', 'V') IS NULL)
DROP VIEW [dbo].[syscollector_execution_stats]
go
CREATE VIEW [dbo].[syscollector_execution_stats] AS
SELECT
log_id,
task_name,
execution_row_count_in,
execution_row_count_out,
execution_row_count_errors,
execution_time_ms,
log_time
FROM dbo.syscollector_execution_stats_internal
go
---------------------------------------------------------------
-- Logging stored procedures
---------------------------------------------------------------
PRINT ''
PRINT 'Creating stored procedure sp_syscollector_verify_event_log_id...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_verify_event_log_id', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_verify_event_log_id]
go
CREATE PROCEDURE [dbo].[sp_syscollector_verify_event_log_id]
@log_id bigint,
@allow_collection_set_id bit = 0
AS
BEGIN
SET NOCOUNT ON
DECLARE @log_id_as_char VARCHAR(36)
IF (@log_id IS NULL)
BEGIN
RAISERROR(14606, -1, -1, '@log_id')
RETURN (1)
END
ELSE IF @allow_collection_set_id = 0
BEGIN
IF (NOT EXISTS (SELECT log_id FROM dbo.syscollector_execution_log WHERE log_id = @log_id AND package_id IS NOT NULL))
BEGIN
SELECT @log_id_as_char = CONVERT(VARCHAR(36), @log_id)
RAISERROR(14262, -1, -1, '@log_id', @log_id_as_char)
RETURN (1)
END
END
ELSE
BEGIN
IF (NOT EXISTS (SELECT log_id FROM dbo.syscollector_execution_log WHERE log_id = @log_id))
BEGIN
SELECT @log_id_as_char = CONVERT(VARCHAR(36), @log_id)
RAISERROR(14262, -1, -1, '@log_id', @log_id_as_char)
RETURN (1)
END
END
RETURN (0)
END
go
PRINT ''
PRINT 'Creating stored procedure sp_syscollector_event_oncollectionstart...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_event_oncollectionstart', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_event_oncollectionstart]
go
CREATE PROCEDURE [dbo].[sp_syscollector_event_oncollectionstart]
@collection_set_id int,
@operator nvarchar(128) = NULL,
@log_id bigint OUTPUT
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_operator')
RETURN(1) -- Failure
END
-- Verify parameters
--
-- Check the collection_set_id
IF (@collection_set_id IS NULL)
BEGIN
RAISERROR(14606, -1, -1, '@collection_set_id')
RETURN (1)
END
ELSE IF (NOT EXISTS (SELECT collection_set_id FROM dbo.syscollector_collection_sets WHERE collection_set_id = @collection_set_id))
BEGIN
DECLARE @collection_set_id_as_char VARCHAR(36)
SELECT @collection_set_id_as_char = CONVERT(VARCHAR(36), @collection_set_id)
RAISERROR(14262, -1, -1, '@collection_set_id', @collection_set_id_as_char)
RETURN (1)
END
-- Default operator to currently logged in user
SET @operator = NULLIF(LTRIM(RTRIM(@operator)), '')
SET @operator = ISNULL(@operator, suser_sname())
-- Insert the log record
--
INSERT INTO dbo.syscollector_execution_log_internal (
parent_log_id,
collection_set_id,
start_time,
last_iteration_time,
finish_time,
runtime_execution_mode,
[status],
operator,
package_id,
package_execution_id,
failure_message
) VALUES (
NULL,
@collection_set_id,
GETDATE(),
NULL,
NULL,
NULL,
0, -- Running
@operator,
NULL,
NULL,
NULL
)
SET @log_id = SCOPE_IDENTITY()
RETURN (0)
END
go
PRINT ''
PRINT 'Creating stored procedure sp_syscollector_event_oncollectionstop...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_event_oncollectionstop', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_event_oncollectionstop]
go
CREATE PROCEDURE [dbo].[sp_syscollector_event_oncollectionstop]
@collection_set_id int
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_proxy'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_proxy')
RETURN(1) -- Failure
END
-- Check the collection_set_id
IF (@collection_set_id IS NULL)
BEGIN
RAISERROR(14606, -1, -1, '@collection_set_id')
RETURN (1)
END
ELSE IF (NOT EXISTS (SELECT collection_set_id FROM dbo.syscollector_collection_sets WHERE collection_set_id = @collection_set_id))
BEGIN
DECLARE @collection_set_id_as_char VARCHAR(36)
SELECT @collection_set_id_as_char = CONVERT(VARCHAR(36), @collection_set_id)
RAISERROR(14262, -1, -1, '@collection_set_id', @collection_set_id_as_char)
RETURN (1)
END
-- Find the log_id
-- It will be a log entry for the same collection set, with no parent and not finished
DECLARE @log_id bigint
SELECT TOP 1 @log_id = log_id FROM dbo.syscollector_execution_log_internal
WHERE collection_set_id = @collection_set_id
AND parent_log_id IS NULL
AND finish_time IS NULL
ORDER BY start_time DESC
IF (@log_id IS NULL)
BEGIN
-- Raise a warning message
RAISERROR(14606, 9, -1, '@log_id')
END
ELSE
BEGIN
-- Mark the log as finished
UPDATE dbo.syscollector_execution_log_internal SET
finish_time = GETDATE(),
[status] = CASE
WHEN [status] = 0 THEN 1 -- Mark complete if it was running
ELSE [status] -- Leave the error status unchanged
END
WHERE log_id = @log_id
END
RETURN (0)
END
go
PRINT ''
PRINT 'Creating stored procedure sp_syscollector_event_oncollectionbegin...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_event_oncollectionbegin', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_event_oncollectionbegin]
go
CREATE PROCEDURE [dbo].[sp_syscollector_event_oncollectionbegin]
@collection_set_id int,
@mode smallint = NULL,
@operator nvarchar(128) = NULL,
@log_id bigint OUTPUT
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_proxy'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_proxy')
RETURN(1) -- Failure
END
-- Verify parameters
--
-- Check the collection_set_id
IF (@collection_set_id IS NULL)
BEGIN
RAISERROR(14606, -1, -1, '@collection_set_id')
RETURN (1)
END
ELSE IF (NOT EXISTS (SELECT collection_set_id FROM dbo.syscollector_collection_sets WHERE collection_set_id = @collection_set_id))
BEGIN
DECLARE @collection_set_id_as_char VARCHAR(36)
SELECT @collection_set_id_as_char = CONVERT(VARCHAR(36), @collection_set_id)
RAISERROR(14262, -1, -1, '@collection_set_id', @collection_set_id_as_char)
RETURN (1)
END
-- Default operator to currently logged in user
SET @operator = NULLIF(LTRIM(RTRIM(@operator)), '')
SET @operator = ISNULL(@operator, suser_sname())
-- Default mode to Collection
SET @mode = ISNULL(@mode, 0)
-- Find the parent log id.
-- It will be a log entry for the same collection set, with no parent and not finished
DECLARE @parent_log_id bigint
SELECT TOP 1 @parent_log_id = log_id FROM dbo.syscollector_execution_log_internal
WHERE collection_set_id = @collection_set_id
AND parent_log_id IS NULL
AND (@mode = 1 OR finish_time IS NULL)
ORDER BY start_time DESC
-- Insert the log record
--
INSERT INTO dbo.syscollector_execution_log_internal (
parent_log_id,
collection_set_id,
collection_item_id,
start_time,
last_iteration_time,
finish_time,
runtime_execution_mode,
[status],
operator,
package_id,
package_execution_id,
failure_message
) VALUES (
@parent_log_id,
@collection_set_id,
NULL,
GETDATE(),
NULL,
NULL,
@mode,
0, -- Running
@operator,
NULL,
NULL,
NULL
)
SET @log_id = SCOPE_IDENTITY()
RETURN (0)
END
go
PRINT ''
PRINT 'Creating stored procedure sp_syscollector_event_oncollectionend...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_event_oncollectionend', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_event_oncollectionend]
go
CREATE PROCEDURE [dbo].[sp_syscollector_event_oncollectionend]
@log_id bigint
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_proxy'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_proxy')
RETURN(1) -- Failure
END
-- Check the log_id
DECLARE @retVal INT
EXEC @retVal = dbo.sp_syscollector_verify_event_log_id @log_id, 1
IF (@retVal <> 0)
RETURN (@retVal)
-- Mark the log as finished
UPDATE dbo.syscollector_execution_log_internal SET
finish_time = GETDATE(),
[status] = CASE
WHEN [status] = 0 THEN 1 -- Mark complete if it was running
ELSE [status] -- Leave the error status unchanged
END
WHERE log_id = @log_id
RETURN (0)
END
go
PRINT ''
PRINT 'Creating stored procedure sp_syscollector_event_onpackagebegin...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_event_onpackagebegin', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_event_onpackagebegin]
go
CREATE PROCEDURE [dbo].[sp_syscollector_event_onpackagebegin]
@parent_log_id bigint,
@package_id uniqueidentifier,
@package_execution_id uniqueidentifier,
@collection_item_id int = NULL,
@mode smallint = NULL,
@operator nvarchar(128) = NULL,
@log_id bigint OUTPUT
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_proxy'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_proxy')
RETURN(1) -- Failure
END
-- Verify parameters
--
-- Check the @parent_log_id
IF (@parent_log_id IS NULL)
BEGIN
RAISERROR(14606, -1, -1, '@parent_log_id')
RETURN (1)
END
ELSE IF (NOT EXISTS (SELECT log_id FROM dbo.syscollector_execution_log WHERE log_id = @parent_log_id))
BEGIN
DECLARE @parent_log_id_as_char VARCHAR(36)
SELECT @parent_log_id_as_char = CONVERT(VARCHAR(36), @parent_log_id)
RAISERROR(14262, -1, -1, '@parent_log_id', @parent_log_id_as_char)
RETURN (1)
END
-- Check the @package_id
IF (@package_id IS NULL)
BEGIN
RAISERROR(14606, -1, -1, '@package_id')
RETURN (1)
END
-- The 84CEC861... package is an id of our special Master package that is allowed to start
-- the log without being saved to sysssispackages
ELSE IF (@package_id != N'84CEC861-D619-433D-86FB-0BB851AF454A' AND NOT EXISTS (SELECT id FROM dbo.sysssispackages WHERE id = @package_id))
BEGIN
DECLARE @package_id_as_char VARCHAR(50)
SELECT @package_id_as_char = CONVERT(VARCHAR(50), @package_id)
RAISERROR(14262, -1, -1, '@package_id', @package_id_as_char)
RETURN (1)
END
-- Default operator to currently logged in user
SET @operator = NULLIF(LTRIM(RTRIM(@operator)), '')
SET @operator = ISNULL(@operator, suser_sname())
-- Default mode to Collection
SET @mode = ISNULL(@mode, 0)
-- Find out the collection_set_id from the parent
DECLARE @collection_set_id INT
SELECT @collection_set_id = collection_set_id FROM dbo.syscollector_execution_log WHERE log_id = @parent_log_id
-- Check the @package_execution_id
IF (@package_execution_id IS NULL)
BEGIN
RAISERROR(14606, -1, -1, '@package_execution_id')
RETURN (1)
END
-- Insert the log record
--
INSERT INTO dbo.syscollector_execution_log_internal (
parent_log_id,
collection_set_id,
collection_item_id,
start_time,
last_iteration_time,
finish_time,
runtime_execution_mode,
[status],
operator,
package_id,
package_execution_id,
failure_message
) VALUES (
@parent_log_id,
@collection_set_id,
@collection_item_id,
GETDATE(),
NULL,
NULL,
@mode,
0, -- Running
@operator,
@package_id,
@package_execution_id,
NULL
)
SET @log_id = SCOPE_IDENTITY()
RETURN (0)
END
go
PRINT ''
PRINT 'Creating stored procedure sp_syscollector_event_onpackageend...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_event_onpackageend', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_event_onpackageend]
go
CREATE PROCEDURE [dbo].[sp_syscollector_event_onpackageend]
@log_id bigint
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_proxy'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_proxy')
RETURN(1) -- Failure
END
-- Check the log_id
DECLARE @retVal INT
EXEC @retVal = dbo.sp_syscollector_verify_event_log_id @log_id
IF (@retVal <> 0)
RETURN (@retVal)
-- Mark the log as finished
UPDATE dbo.syscollector_execution_log_internal SET
finish_time = GETDATE(),
[status] = CASE
WHEN [status] = 0 THEN 1 -- Mark complete if it was running
ELSE [status] -- Leave the error status unchanged
END
WHERE log_id = @log_id
DECLARE @runtime_execution_mode smallint
DECLARE @status smallint
SELECT @status = [status], @runtime_execution_mode = runtime_execution_mode
FROM dbo.syscollector_execution_log_internal
WHERE log_id = @log_id
-- status was successful and this is logged by an upload package
IF @status = 1 AND @runtime_execution_mode = 1
BEGIN
-- if the package ended succesfully, update the top most log to warning if it had failure
-- this is because if there were a previous upload failure but the latest upload were successful,
-- we want indicated a warning rather than a failure throughout the lifetime of this collection set
DECLARE @parent_log_id BIGINT
SELECT @parent_log_id = parent_log_id FROM dbo.syscollector_execution_log_internal WHERE log_id = @log_id;
WHILE @parent_log_id IS NOT NULL
BEGIN
-- get the next parent
SET @log_id = @parent_log_id
SELECT @parent_log_id = parent_log_id FROM dbo.syscollector_execution_log_internal WHERE log_id = @log_id;
END
UPDATE dbo.syscollector_execution_log_internal SET
[status] = CASE
WHEN [status] = 2 THEN 3 -- Mark warning if it indicated a failure
ELSE [status] -- Leave the original status unchanged
END
WHERE
log_id = @log_id
END
RETURN (0)
END
go
PRINT ''
PRINT 'Creating stored procedure sp_syscollector_event_onpackageupdate...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_event_onpackageupdate', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_event_onpackageupdate]
go
CREATE PROCEDURE [dbo].[sp_syscollector_event_onpackageupdate]
@log_id bigint
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_proxy'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_proxy')
RETURN(1) -- Failure
END
-- Check the log_id
DECLARE @retVal INT
EXEC @retVal = dbo.sp_syscollector_verify_event_log_id @log_id
IF (@retVal <> 0)
RETURN (@retVal)
-- Update the log
UPDATE dbo.syscollector_execution_log_internal SET
last_iteration_time = GETDATE()
WHERE log_id = @log_id
RETURN (0)
END
go
PRINT ''
PRINT 'Creating stored procedure sp_syscollector_event_onerror...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_event_onerror', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_event_onerror]
go
CREATE PROCEDURE [dbo].[sp_syscollector_event_onerror]
@log_id bigint,
@message nvarchar(2048) = NULL
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_proxy'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_proxy')
RETURN(1) -- Failure
END
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_event_onerror
ELSE
BEGIN TRANSACTION
BEGIN TRY
-- Check the log_id
-- If @message is passed, we can allow to enter the error for a collection set
-- otherwise we will rely on the entries in sysssislog table to get the error message.
DECLARE @retVal INT
IF (@message IS NULL)
BEGIN
EXEC @retVal = dbo.sp_syscollector_verify_event_log_id @log_id, 0
END
ELSE
BEGIN
EXEC @retVal = dbo.sp_syscollector_verify_event_log_id @log_id, 1
END
IF (@retVal <> 0)
RETURN (@retVal)
DECLARE
@failure_message NVARCHAR(2048)
,@execution_id UNIQUEIDENTIFIER
IF @message IS NULL
BEGIN
-- If no message is provided, find the last task that has failed
-- for this package in the sysssislog table.
-- Store the message as the failure_message for our package log.
SELECT
@execution_id = package_execution_id
FROM dbo.syscollector_execution_log
WHERE log_id = @log_id
SELECT TOP 1
@failure_message = [message]
FROM dbo.sysssislog
WHERE executionid = @execution_id
AND (UPPER([event] COLLATE SQL_Latin1_General_CP1_CS_AS) = 'ONERROR')
ORDER BY endtime DESC
END
ELSE
BEGIN
-- Otherwise use the provided message
SET @failure_message = @message
END
-- Update the execution log
UPDATE dbo.syscollector_execution_log_internal SET
[status] = 2 -- Mark as Failed
,failure_message = @failure_message
WHERE
log_id = @log_id
-- Update all parent logs with the failure status
SELECT @log_id = parent_log_id FROM dbo.syscollector_execution_log_internal WHERE log_id = @log_id;
WHILE @log_id IS NOT NULL
BEGIN
UPDATE dbo.syscollector_execution_log_internal SET
[status] = 2 -- Mark as Failed
WHERE
log_id = @log_id;
-- get the next parent
SELECT @log_id = parent_log_id FROM dbo.syscollector_execution_log_internal WHERE log_id = @log_id;
END
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_event_onerror
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
go
PRINT ''
PRINT 'Creating stored procedure sp_syscollector_event_onstatsupdate...'
IF (NOT OBJECT_ID('dbo.sp_syscollector_event_onstatsupdate', 'P') IS NULL)
DROP PROCEDURE [dbo].[sp_syscollector_event_onstatsupdate]
go
CREATE PROCEDURE [dbo].[sp_syscollector_event_onstatsupdate]
@log_id bigint,
@task_name nvarchar(128),
@row_count_in int = NULL,
@row_count_out int = NULL,
@row_count_error int = NULL,
@execution_time_ms int = NULL
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_proxy'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_proxy')
RETURN(1) -- Failure
END
-- Check the log_id
DECLARE @retVal INT
EXEC @retVal = dbo.sp_syscollector_verify_event_log_id @log_id
IF (@retVal <> 0)
RETURN (@retVal)
-- Check task name
IF (@task_name IS NOT NULL)
BEGIN
SET @task_name = NULLIF(LTRIM(RTRIM(@task_name)), N'')
END
IF (@task_name IS NULL)
BEGIN
RAISERROR(14606, -1, -1, '@task_name')
RETURN (1)
END
-- Insert the log entry
INSERT INTO dbo.syscollector_execution_stats_internal (
log_id,
task_name,
execution_row_count_in,
execution_row_count_out,
execution_row_count_errors,
execution_time_ms,
log_time
) VALUES (
@log_id,
@task_name,
@row_count_in,
@row_count_out,
@row_count_error,
NULLIF(@execution_time_ms, 0),
GETDATE()
)
RETURN (0)
END
go
---------------------------------------------------------------
-- Data Collector log viewing functions and views
---------------------------------------------------------------
-- [fn_syscollector_find_collection_set_root]
-- This function finds the first log entry for a given collection set
-- run. It retunrs log_id of that entry.
PRINT ''
PRINT 'Creating function [dbo].[fn_syscollector_find_collection_set_root] ...'
IF (NOT OBJECT_ID(N'dbo.fn_syscollector_find_collection_set_root', 'FN') IS NULL)
DROP FUNCTION [dbo].[fn_syscollector_find_collection_set_root]
go
CREATE FUNCTION [dbo].[fn_syscollector_find_collection_set_root]
(
@log_id BIGINT
)
RETURNS BIGINT
WITH RETURNS NULL ON NULL INPUT
AS
BEGIN
DECLARE @root_id BIGINT;
-- Derive result using a CTE as the table is self-referencing
WITH graph AS
(
-- select the anchor (specified) node
SELECT log_id, parent_log_id FROM dbo.syscollector_execution_log WHERE log_id = @log_id
UNION ALL
-- select the parent node recursively
SELECT node.log_id, node.parent_log_id FROM dbo.syscollector_execution_log node
INNER JOIN graph AS leaf ON (node.log_id = leaf.parent_log_id)
)
SELECT @root_id = log_id FROM graph WHERE parent_log_id = 0;
--Return result
RETURN ISNULL(@root_id, @log_id)
END
go
-- [fn_syscollector_get_execution_log_tree]
-- This function returns a set of log entries related to a single run
-- of a collection set. The entries are ordered in a hierarchy, starting from
-- the collection set first log entry and then down through all packages
-- that were executed as part of the collection set.
PRINT ''
PRINT 'Creating function [dbo].[fn_syscollector_get_execution_log_tree] ...'
IF (NOT OBJECT_ID(N'dbo.fn_syscollector_get_execution_log_tree', 'IF') IS NULL)
DROP FUNCTION [dbo].[fn_syscollector_get_execution_log_tree]
go
CREATE FUNCTION [dbo].[fn_syscollector_get_execution_log_tree]
(
@log_id BIGINT,
@from_collection_set BIT = 1
)
RETURNS TABLE
AS
RETURN
(
-- Derive result using a CTE as the table is self-referencing
WITH graph AS
(
-- select the anchor (specified) node
SELECT
log_id,
parent_log_id,
collection_set_id,
start_time,
last_iteration_time,
finish_time,
runtime_execution_mode,
operator,
[status],
package_id,
package_execution_id,
failure_message,
0 AS depth
FROM dbo.syscollector_execution_log
WHERE log_id = CASE @from_collection_set
WHEN 1 THEN dbo.fn_syscollector_find_collection_set_root(@log_id)
ELSE @log_id
END
-- select the child nodes recursively
UNION ALL
SELECT
leaf.log_id,
leaf.parent_log_id,
leaf.collection_set_id,
leaf.start_time,
leaf.last_iteration_time,
leaf.finish_time,
leaf.runtime_execution_mode,
leaf.operator,
leaf.[status],
leaf.package_id,
leaf.package_execution_id,
leaf.failure_message,
node.depth + 1 AS depth
FROM dbo.syscollector_execution_log AS leaf
INNER JOIN graph AS node ON (node.log_id = leaf.parent_log_id)
)
SELECT
log_id,
parent_log_id,
collection_set_id,
start_time,
last_iteration_time,
finish_time,
CASE
WHEN finish_time IS NOT NULL THEN DATEDIFF(ss, start_time, finish_time)
WHEN last_iteration_time IS NOT NULL THEN DATEDIFF(ss, start_time, last_iteration_time)
ELSE 0
END AS duration,
runtime_execution_mode,
operator,
[status],
package_id,
package_execution_id,
failure_message,
depth
FROM graph
)
go
-- [fn_syscollector_get_execution_stats]
-- This function returns stats for each execution of a package.
-- The stats should be logged for each iteration within the package.
PRINT ''
PRINT 'Creating function [dbo].[fn_syscollector_get_execution_stats] ...'
IF (NOT OBJECT_ID(N'dbo.fn_syscollector_get_execution_stats', 'IF') IS NULL)
DROP FUNCTION [dbo].[fn_syscollector_get_execution_stats]
go
CREATE FUNCTION [dbo].[fn_syscollector_get_execution_stats]
(
@log_id BIGINT
)
RETURNS TABLE
AS
RETURN
(
SELECT
log_id,
task_name,
AVG(execution_row_count_in) AS avg_row_count_in,
MIN(execution_row_count_in) AS min_row_count_in,
MAX(execution_row_count_in) AS max_row_count_in,
AVG(execution_row_count_out) AS avg_row_count_out,
MIN(execution_row_count_out) AS min_row_count_out,
MAX(execution_row_count_out) AS max_row_count_out,
AVG(execution_row_count_errors) AS avg_row_count_errors,
MIN(execution_row_count_errors) AS min_row_count_errors,
MAX(execution_row_count_errors) AS max_row_count_errors,
AVG(execution_time_ms) AS avg_duration,
MIN(execution_time_ms) AS min_duration,
MAX(execution_time_ms) AS max_duration
FROM dbo.syscollector_execution_stats
WHERE log_id = @log_id
GROUP BY log_id, task_name
)
go
-- [fn_syscollector_get_execution_details]
-- This function returns detailed log entries from SSIS log for each package
-- execution. The log id passed as input is an id of a log entry for that package
-- from syscollector_execution_log view.
PRINT ''
PRINT 'Creating function [dbo].[fn_syscollector_get_execution_details] ...'
IF (NOT OBJECT_ID(N'dbo.fn_syscollector_get_execution_details', 'IF') IS NULL)
DROP FUNCTION [dbo].[fn_syscollector_get_execution_details]
go
CREATE FUNCTION [dbo].[fn_syscollector_get_execution_details]
(
@log_id BIGINT
)
RETURNS TABLE
AS
RETURN
(
SELECT TOP (100) PERCENT
l.source,
l.event,
l.message,
l.starttime AS start_time,
l.endtime AS finish_time,
l.datacode,
l.databytes
FROM sysssislog l
JOIN dbo.syscollector_execution_log e ON (e.package_execution_id = l.executionid)
WHERE e.log_id = @log_id
ORDER BY l.starttime
)
go
-- [syscollector_execution_log_full]
-- An expanded log view that shows the log entries in a hierarchical order.
PRINT ''
PRINT 'Creating view syscollector_execution_log_full...'
IF (NOT OBJECT_ID('dbo.syscollector_execution_log_full', 'V') IS NULL)
DROP VIEW [dbo].[syscollector_execution_log_full]
go
CREATE VIEW [dbo].[syscollector_execution_log_full]
AS
SELECT
t.log_id,
ISNULL(t.parent_log_id, 0) as parent_log_id,
CASE
WHEN t.package_id IS NULL THEN SPACE(t.depth * 4) + c.name
WHEN t.package_id = N'84CEC861-D619-433D-86FB-0BB851AF454A' THEN SPACE(t.depth * 4) + N'Master'
ELSE SPACE(t.depth * 4) + p.name
END AS [name],
t.[status],
t.runtime_execution_mode,
t.start_time,
t.last_iteration_time,
t.finish_time,
t.duration,
t.failure_message,
t.operator,
t.package_execution_id,
t.collection_set_id
FROM dbo.syscollector_execution_log_internal l
CROSS APPLY dbo.fn_syscollector_get_execution_log_tree(l.log_id, 0) t
LEFT OUTER JOIN dbo.syscollector_collection_sets c ON( c.collection_set_id = t.collection_set_id)
LEFT OUTER JOIN dbo.sysssispackages p ON (p.id = t.package_id AND p.id != N'84CEC861-D619-433D-86FB-0BB851AF454A')
WHERE l.parent_log_id IS NULL
go
---------------------------------------------------------------
-- Data Collection log clean-up
---------------------------------------------------------------
-- [sp_syscollector_delete_execution_log_tree]
-- This stored procedure removes all log entries related to a single
-- run of a collection set. It also removes corresponding log entries
-- from SSIS log tables.
PRINT ''
IF (NOT OBJECT_ID(N'dbo.sp_syscollector_delete_execution_log_tree', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_delete_execution_log_tree] ...'
DROP PROCEDURE [dbo].[sp_syscollector_delete_execution_log_tree]
END
go
PRINT 'Creating procedure [dbo].[sp_syscollector_delete_execution_log_tree] ...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_delete_execution_log_tree]
@log_id BIGINT,
@from_collection_set BIT = 1
AS
BEGIN
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_operator')
RETURN(1) -- Failure
END
SET NOCOUNT ON;
CREATE TABLE #log_ids (log_id BIGINT);
WITH graph AS
(
SELECT log_id FROM dbo.syscollector_execution_log
WHERE log_id = CASE @from_collection_set
WHEN 1 THEN dbo.fn_syscollector_find_collection_set_root(@log_id)
ELSE @log_id
END
UNION ALL
SELECT leaf.log_id FROM dbo.syscollector_execution_log AS leaf
INNER JOIN graph AS node ON (node.log_id = leaf.parent_log_id)
)
INSERT INTO #log_ids
SELECT log_id
FROM graph
-- Delete all ssis log records pertaining to the selected logs
DELETE FROM dbo.sysssislog
FROM dbo.sysssislog AS s
INNER JOIN dbo.syscollector_execution_log_internal AS l ON (l.package_execution_id = s.executionid)
INNER JOIN #log_ids AS i ON i.log_id = l.log_id
-- Then delete the actual logs
DELETE FROM syscollector_execution_log_internal
FROM syscollector_execution_log_internal AS l
INNER Join #log_ids AS i ON i.log_id = l.log_id
DROP TABLE #log_ids
RETURN (0)
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_delete_collection_set_internal]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_delete_collection_set_internal]...'
DROP PROCEDURE [dbo].[sp_syscollector_delete_collection_set_internal]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_delete_collection_set_internal]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_delete_collection_set_internal]
@collection_set_id int,
@name sysname,
@collection_job_id uniqueidentifier,
@upload_job_id uniqueidentifier,
@collection_mode smallint
AS
BEGIN
DECLARE @TranCounter int
SET @TranCounter = @@TRANCOUNT
IF (@TranCounter > 0)
SAVE TRANSACTION tran_delete_collection_set
ELSE
BEGIN TRANSACTION
BEGIN TRY
-- clean log before deleting collection set
DECLARE @log_id bigint
SET @log_id = (SELECT TOP(1) log_id FROM dbo.syscollector_execution_log WHERE collection_set_id = @collection_set_id)
WHILE (@log_id IS NOT NULL)
BEGIN
EXEC dbo.sp_syscollector_delete_execution_log_tree @log_id = @log_id
SET @log_id = (SELECT TOP(1) log_id FROM dbo.syscollector_execution_log WHERE collection_set_id = @collection_set_id)
END
DECLARE @schedule_id int
SELECT @schedule_id = schedule_id
FROM dbo.syscollector_collection_sets cs JOIN sysschedules_localserver_view sv
ON (cs.schedule_uid = sv.schedule_uid)
WHERE collection_set_id = @collection_set_id
DELETE [dbo].[syscollector_collection_sets_internal]
WHERE collection_set_id = @collection_set_id
EXEC dbo.sp_syscollector_delete_jobs
@collection_job_id = @collection_job_id,
@upload_job_id = @upload_job_id,
@schedule_id = @schedule_id,
@collection_mode = @collection_mode
IF (@TranCounter = 0)
COMMIT TRANSACTION
RETURN (0)
END TRY
BEGIN CATCH
IF (@TranCounter = 0 OR XACT_STATE() = -1)
ROLLBACK TRANSACTION
ELSE IF (XACT_STATE() = 1)
ROLLBACK TRANSACTION tran_delete_collection_set
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, @ErrorSeverity, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
RETURN (1)
END CATCH
END
GO
-- This is a stored procedure of collection_set, but it is created here because it
-- makes references to the collection item view, execution log,
-- and the [sp_syscollector_delete_execution_log_tree] stored proc
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_delete_collection_set]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_delete_collection_set]...'
DROP PROCEDURE [dbo].[sp_syscollector_delete_collection_set]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_delete_collection_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_delete_collection_set]
@collection_set_id int = NULL,
@name sysname = NULL
WITH EXECUTE AS OWNER -- 'MS_DataCollectorInternalUser'
AS
BEGIN
-- Security check (role membership)
EXECUTE AS CALLER;
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
REVERT;
RAISERROR(14677, -1, -1, 'dc_admin')
RETURN (1)
END
REVERT;
DECLARE @retVal int
EXEC @retVal = dbo.sp_syscollector_verify_collection_set @collection_set_id OUTPUT, @name OUTPUT
IF (@retVal <> 0)
RETURN (1)
DECLARE @is_system bit
DECLARE @is_running bit
DECLARE @upload_job_id uniqueidentifier
DECLARE @collection_job_id uniqueidentifier
DECLARE @collection_mode smallint
SELECT @is_running = is_running,
@is_system = is_system,
@upload_job_id = upload_job_id,
@collection_job_id = collection_job_id,
@collection_mode = collection_mode
FROM [dbo].[syscollector_collection_sets]
WHERE collection_set_id = @collection_set_id
IF (@is_system = 1)
BEGIN
-- cannot update, delete, or add new collection items to a system collection set
RAISERROR(14696, -1, -1);
RETURN (1)
END
IF (@is_running = 1)
BEGIN
EXEC @retVal = sp_syscollector_stop_collection_set @collection_set_id = @collection_set_id
IF (@retVal <> 0)
RETURN (1)
END
-- All checks are go
-- Do the actual delete
EXEC @retVal = sp_syscollector_delete_collection_set_internal
@collection_set_id = @collection_set_id,
@name = @name,
@collection_job_id = @collection_job_id,
@upload_job_id = @upload_job_id,
@collection_mode = @collection_mode
RETURN (0)
END
GO
IF (NOT OBJECT_ID('dbo.sp_syscollector_purge_collection_logs', 'P') IS NULL)
BEGIN
PRINT ''
PRINT 'Dropping stored procedure sp_syscollector_purge_collection_logs...'
DROP PROCEDURE [dbo].[sp_syscollector_purge_collection_logs]
END
GO
-- [sp_syscollector_purge_collection_logs]
-- The sp cleans any log record with an expired finish date
-- Expiration is measured from the date provided to the sp
-- and defaults to TODAY.
-- optional parameter @delete_batch_size - specifies max number of log records
-- to delete in single iteration
PRINT ''
PRINT 'Creating stored procedure sp_syscollector_purge_collection_logs...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_purge_collection_logs]
@reference_date datetime = NULL,
@delete_batch_size int = 500
AS
BEGIN
SET NOCOUNT ON
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_proxy'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_proxy')
RETURN(1) -- Failure
END
IF (@reference_date IS NULL)
BEGIN
SET @reference_date = GETDATE()
END
-- An expired log record is any record of a collection set that is older than
-- the reference date minus the collection set's days_until_expiration
CREATE TABLE #purged_log_ids (log_id BIGINT, package_execution_id uniqueidentifier)
-- Identify logs to purge based on following criteria
-- a) limit max batch size
-- b) do not delete last log record that is a root log record for a collection set
INSERT INTO #purged_log_ids
SELECT TOP (@delete_batch_size) log_id, package_execution_id
FROM syscollector_execution_log_internal as l
INNER JOIN syscollector_collection_sets s ON l.collection_set_id = s.collection_set_id
WHERE s.days_until_expiration > 0
AND @reference_date >= DATEADD(DAY, s.days_until_expiration, l.finish_time)
AND log_id NOT IN (
SELECT TOP 1 log_id from syscollector_execution_log_internal
WHERE parent_log_id IS NULL
AND collection_set_id = l.collection_set_id
ORDER BY start_time DESC
)
DECLARE @purge_log_count int
SELECT @purge_log_count = COUNT(log_id)
FROM #purged_log_ids
-- Delete all ssis log records pertaining to expired logs
DELETE FROM dbo.sysssislog
FROM dbo.sysssislog AS s
INNER JOIN #purged_log_ids AS i ON i.package_execution_id = s.executionid
-- Then delete the actual logs
DELETE FROM syscollector_execution_log_internal
FROM syscollector_execution_log_internal AS l
INNER Join #purged_log_ids AS i ON i.log_id = l.log_id
DROP TABLE #purged_log_ids
-- making sure that delete # record does not exceed given delete batch size
DECLARE @orphaned_record_cleanup_count int
SET @orphaned_record_cleanup_count = @delete_batch_size - @purge_log_count
-- Go for another round to cleanup the orphans
-- Ideally, the log heirarchy guarantees that a finish time by a parent log will always
-- be higher than the finish time of any of its descendants.
-- The purge step however does not delete log records with a null finish time
-- A child log can have a null finish time while its parent is closed if there is an
-- error in execution that causes the log to stay open.
-- If such a child log exists, its parent will be purged leaving it as an orphan
-- get orphan records and all their descendants in a cursor and purge them
DECLARE orphaned_log_cursor INSENSITIVE CURSOR FOR
SELECT TOP (@orphaned_record_cleanup_count) log_id
FROM syscollector_execution_log_internal
WHERE parent_log_id NOT IN (
SELECT log_id FROM syscollector_execution_log_internal
)
FOR READ ONLY
DECLARE @log_id BIGINT
-- for every orphan, delete all its remaining tree
-- this is supposedly a very small fraction of the entire log
OPEN orphaned_log_cursor
FETCH orphaned_log_cursor INTO @log_id
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC sp_syscollector_delete_execution_log_tree @log_id = @log_id, @from_collection_set = 0
FETCH orphaned_log_cursor INTO @log_id
END
CLOSE orphaned_log_cursor
DEALLOCATE orphaned_log_cursor
END
GO
---------------------------------------------------------------
-- Start and stop Data Collector
---------------------------------------------------------------
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_enable_collector]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_enable_collector]...'
DROP PROCEDURE [dbo].[sp_syscollector_enable_collector]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_enable_collector]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_enable_collector]
WITH EXECUTE AS OWNER -- 'MS_DataCollectorInternalUser'
AS
BEGIN
-- Security check (role membership)
EXECUTE AS CALLER;
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
REVERT;
RAISERROR(14677, -1, -1, 'dc_operator')
RETURN(1) -- Failure
END
REVERT;
-- check if SQL Server Agent is enabled
DECLARE @agent_enabled int
SELECT @agent_enabled = CAST(value_in_use AS int) FROM sys.configurations WHERE name = N'Agent XPs'
IF @agent_enabled <> 1
BEGIN
RAISERROR(14699, -1, -1)
RETURN (1) -- Failure
END
REVERT;
BEGIN TRANSACTION
DECLARE @was_enabled int;
SELECT @was_enabled = ISNULL(CONVERT(int, parameter_value),0)
FROM [dbo].[syscollector_config_store_internal]
WHERE parameter_name = 'CollectorEnabled'
IF (@was_enabled = 0)
BEGIN
UPDATE [dbo].[syscollector_config_store_internal]
SET parameter_value = 1
WHERE parameter_name = 'CollectorEnabled'
DECLARE @collection_set_id int
DECLARE collection_set_cursor CURSOR LOCAL FOR
SELECT collection_set_id
FROM dbo.syscollector_collection_sets
WHERE is_running = 1
OPEN collection_set_cursor
FETCH collection_set_cursor INTO @collection_set_id
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC dbo.sp_syscollector_start_collection_set_jobs @collection_set_id = @collection_set_id
FETCH collection_set_cursor INTO @collection_set_id
END
CLOSE collection_set_cursor
DEALLOCATE collection_set_cursor
END
COMMIT TRANSACTION
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_disable_collector]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_disable_collector]...'
DROP PROCEDURE [dbo].[sp_syscollector_disable_collector]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_disable_collector]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_disable_collector]
WITH EXECUTE AS OWNER -- 'MS_DataCollectorInternalUser'
AS
BEGIN
-- Security check (role membership)
EXECUTE AS CALLER;
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
REVERT;
RAISERROR(14677, -1, -1, 'dc_operator')
RETURN(1) -- Failure
END
REVERT;
BEGIN TRANSACTION
DECLARE @was_enabled int;
SELECT @was_enabled = ISNULL(CONVERT(int, parameter_value),0)
FROM [dbo].[syscollector_config_store_internal]
WHERE parameter_name = 'CollectorEnabled'
IF (@was_enabled <> 0)
BEGIN
UPDATE [dbo].[syscollector_config_store_internal]
SET parameter_value = 0
WHERE parameter_name = 'CollectorEnabled'
DECLARE @collection_set_id INT
DECLARE @collection_mode SMALLINT
DECLARE @collection_job_id UNIQUEIDENTIFIER
DECLARE collection_set_cursor CURSOR LOCAL FOR
SELECT collection_set_id, collection_mode, collection_job_id
FROM dbo.syscollector_collection_sets
WHERE is_running = 1
OPEN collection_set_cursor
FETCH collection_set_cursor INTO @collection_set_id, @collection_mode, @collection_job_id
WHILE @@FETCH_STATUS = 0
BEGIN
-- If this collection set is running in cached mode, and the collection job is running, we need to stop the job explicitly here
DECLARE @is_collection_job_running INT
EXECUTE [dbo].[sp_syscollector_get_collection_set_execution_status]
@collection_set_id = @collection_set_id,
@is_collection_running = @is_collection_job_running OUTPUT
IF (@is_collection_job_running = 1
AND @collection_mode = 0) -- Cached mode
BEGIN
EXEC sp_stop_job @job_id = @collection_job_id
END
-- Now, disable the jobs and detach them from the upload schedules
EXEC dbo.sp_syscollector_stop_collection_set_jobs @collection_set_id = @collection_set_id
FETCH collection_set_cursor INTO @collection_set_id, @collection_mode, @collection_job_id
END
CLOSE collection_set_cursor
DEALLOCATE collection_set_cursor
END
COMMIT TRANSACTION
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_get_trace_info]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_get_trace_info]'
DROP PROCEDURE [dbo].[sp_syscollector_get_trace_info]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_get_trace_info]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_get_trace_info]
@trace_path nvarchar(512),
@use_default int
AS
BEGIN
SELECT
CONVERT(nvarchar(30), t.start_time, 126) as start_time,
CASE t.status
WHEN 1 THEN 1
ELSE 0
END AS is_running,
ISNULL(t.dropped_event_count,0) as dropped_event_count,
t.id
FROM sys.traces t
WHERE (@use_default=1 and t.is_default=1)
OR (@use_default=0 AND t.path LIKE (@trace_path + N'%.trc'))
END
GO
---------------------------------------------------------------
-- Data Collector: Helper procedures
---------------------------------------------------------------
-- Procedure to retrieve a query plan from cache
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_text_query_plan_lookpup]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_text_query_plan_lookpup]'
DROP PROCEDURE [dbo].[sp_syscollector_text_query_plan_lookpup]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_text_query_plan_lookpup]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_text_query_plan_lookpup]
@plan_handle varbinary(64),
@statement_start_offset int,
@statement_end_offset int
AS
BEGIN
SET NOCOUNT ON
SELECT
@plan_handle AS plan_handle,
@statement_start_offset AS statement_start_offset,
@statement_end_offset AS statement_end_offset,
[dbid] AS database_id,
[objectid] AS object_id,
OBJECT_NAME(objectid, dbid) AS object_name,
[query_plan] AS query_plan
FROM
[sys].[dm_exec_text_query_plan](@plan_handle, @statement_start_offset, @statement_end_offset) dm
END
GO
-- Procedure to retrieve a query text from cache
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_sql_text_lookup]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_sql_text_lookup]'
DROP PROCEDURE [dbo].[sp_syscollector_sql_text_lookup]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_sql_text_lookup]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_sql_text_lookup]
@sql_handle varbinary(64)
AS
BEGIN
SET NOCOUNT ON
SELECT
@sql_handle as sql_handle,
dm.[dbid] AS database_id,
dm.[objectid] AS object_id,
OBJECT_NAME(objectid, dbid) AS object_name,
CASE dm.[encrypted]
WHEN 1 THEN N'Query SQL Text Encrypted'
ELSE dm.[text]
END AS sql_text
FROM
[sys].[dm_exec_sql_text](@sql_handle) dm
END
GO
---------------------------------------------------------------
-- Install out-of-the-box objects
---------------------------------------------------------------
PRINT 'Installing out of the box Collector objects'
PRINT ''
-- We need agent XP's to be on for many parts of the coming installation script
-- Enable them here once and return them to their original state when done
DECLARE @advopt_old_value int
DECLARE @comp_old_value int
EXEC #sp_enable_component 'Agent XPs', @advopt_old_value out, @comp_old_value out
-- We need the old values to endure beyond batches
-- insert them into temp tables
IF (OBJECT_ID('tempdb..#advopt_old_value', 'U') IS NOT NULL)
BEGIN
DROP TABLE #advopt_old_value
END
SELECT @advopt_old_value AS advopt_old_value
INTO #advopt_old_value
IF (OBJECT_ID('tempdb..#comp_old_value', 'U') IS NOT NULL)
BEGIN
DROP TABLE #comp_old_value
END
SELECT @comp_old_value AS comp_old_value
INTO #comp_old_value
GO
-- disable the collector first
EXEC sp_syscollector_disable_collector
GO
---------------------------------------------------------------
-- Out-of-the-box SSIS folders for Data Collector
---------------------------------------------------------------
PRINT 'Creating SSIS folders...'
-- create 'Data Collector' folder under the root
IF(NOT EXISTS(SELECT *
FROM dbo.sysssispackagefolders
WHERE folderid = '8877FE4B-A938-4a51-84B9-C5BDAD74B0AD'))
BEGIN
EXEC dbo.sp_ssis_addfolder
@parentfolderid = '00000000-0000-0000-0000-000000000000',
@name = 'Data Collector',
@folderid = '8877FE4B-A938-4a51-84B9-C5BDAD74B0AD'
END
GO
-- create 'Generated' folder under 'Data Collector'
IF(NOT EXISTS(SELECT *
FROM dbo.sysssispackagefolders
WHERE folderid = '39163C42-602B-42C9-B4F7-1843614F9625'))
BEGIN
EXEC dbo.sp_ssis_addfolder
@parentfolderid = '8877FE4B-A938-4a51-84B9-C5BDAD74B0AD',
@name = 'Generated',
@folderid = '39163C42-602B-42c9-B4F7-1843614F9625'
END
GO
---------------------------------------------------------------
-- Loading instmdw.sql
---------------------------------------------------------------
-- a data collector table to store BLOB
IF (OBJECT_ID(N'[dbo].[syscollector_blobs_internal]', 'U') IS NULL)
BEGIN
PRINT 'Creating table [dbo].[syscollector_blobs_internal]...'
CREATE TABLE [dbo].[syscollector_blobs_internal] (
parameter_name nvarchar(128) NOT NULL,
parameter_value varbinary(max) NOT NULL,
CONSTRAINT [PK_syscollector_blobs_internal_paremeter_name] PRIMARY KEY CLUSTERED (parameter_name ASC)
)
END
GO
-- an SP to read a parameter value from the syscollector BLOB table
-- this stored procedure is called by the wizard to retrieve the instmdw.sql when setting up MDW
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_get_instmdw]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_get_instmdw]'
DROP PROCEDURE [dbo].[sp_syscollector_get_instmdw]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_get_instmdw]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_get_instmdw]
AS
BEGIN
-- only dc_admin and dbo can setup MDW
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14712, -1, -1) WITH LOG
RETURN(1) -- Failure
END
-- if the script has not been loaded, load it now
IF (NOT EXISTS(SELECT parameter_name
FROM syscollector_blobs_internal
WHERE parameter_name = N'InstMDWScript'))
BEGIN
EXECUTE sp_syscollector_upload_instmdw
END
SELECT cast(parameter_value as nvarchar(max))
FROM syscollector_blobs_internal
WHERE parameter_name = N'InstMDWScript'
END
GO
-- the script that would upload or update instmdw.sql
-- this is used when a hotfix, service pack, or upgrade is issued in instmdw.sql
-- user can specify the path to the new instmdw.sql to be installed or updated to.
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_upload_instmdw]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_upload_instmdw]'
DROP PROCEDURE [dbo].[sp_syscollector_upload_instmdw]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_upload_instmdw]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_upload_instmdw]
@installpath nvarchar(2048) = NULL
AS
BEGIN
-- only dc_admin and dbo can setup MDW
IF (NOT (ISNULL(IS_MEMBER(N'dc_admin'), 0) = 1) AND NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14712, -1, -1) WITH LOG
RETURN(1) -- Failure
END
IF (@installpath IS NULL)
BEGIN
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\MSSQLServer\Setup', N'SQLPath', @installpath OUTPUT;
IF RIGHT(@installpath, 1) != N'\' set @installpath = @installpath + N'\'
SET @installpath = @installpath + N'Install\'
END
DECLARE @filename nvarchar(2048);
SET @filename = @installpath + N'instmdw.sql'
PRINT 'Uploading instmdw.sql from disk: ' + @filename
CREATE TABLE #bulkuploadinstmdwscript
(
[instmdwscript] nvarchar(max) NOT NULL
);
DECLARE @stmt_bulkinsert nvarchar(2048);
SET @stmt_bulkinsert = N'
BULK INSERT #bulkuploadinstmdwscript
FROM '
-- Escape any embedded single quotes (we can't use QUOTENAME here b/c it can't handle strings > 128 chars)
+ '''' + REPLACE(@filename COLLATE database_default, N'''', N'''''') + '''
WITH
(
DATAFILETYPE = ''char'',
FIELDTERMINATOR = ''dc:stub:ft'',
ROWTERMINATOR = ''dc:stub:rt'',
CODEPAGE = ''RAW''
);
';
EXECUTE sp_executesql @stmt_bulkinsert;
DECLARE @bytesLoaded int
SELECT @bytesLoaded = ISNULL (DATALENGTH ([instmdwscript]), 0) FROM #bulkuploadinstmdwscript
PRINT 'Loaded ' + CONVERT (nvarchar, @bytesLoaded)
+ ' bytes from ' + '''' + REPLACE(@filename COLLATE database_default, N'''', N'''''') + ''''
DECLARE @scriptdata varbinary(max)
SELECT @scriptdata = convert(varbinary(max), [instmdwscript]) FROM #bulkuploadinstmdwscript;
IF (EXISTS(SELECT * FROM [dbo].[syscollector_blobs_internal]
WHERE parameter_name = N'InstMDWScript'))
BEGIN
UPDATE [dbo].[syscollector_blobs_internal]
SET parameter_value = @scriptdata
WHERE parameter_name = N'InstMDWScript'
END
ELSE
BEGIN
INSERT INTO [dbo].[syscollector_blobs_internal] (
parameter_name,
parameter_value
)
VALUES
(
N'InstMDWScript',
@scriptdata
)
END
DROP TABLE #bulkuploadinstmdwscript
END
GO
---------------------------------------------------------------
-- Out-of-the-box data collector packages - loading SSIS packages
---------------------------------------------------------------
CREATE PROCEDURE #syscollector_upload_package_from_file
@filename nvarchar(2048),
@packagename sysname,
@packageid uniqueidentifier,
@versionid uniqueidentifier
AS
BEGIN
RAISERROR ('Uploading data collector package from disk: %s', 0, 1, @filename) WITH NOWAIT;
CREATE TABLE #bulkpackage
(
[packagexml] xml NOT NULL
);
DECLARE @stmt_bulkinsert nvarchar(2048);
SET @stmt_bulkinsert = N'
BULK INSERT #bulkpackage
FROM '
-- Escape any embedded single quotes (we can't use QUOTENAME here b/c it can't handle strings > 128 chars)
+ '''' + REPLACE(@filename COLLATE database_default, N'''', N'''''') + '''
WITH
(
DATAFILETYPE = ''char'',
FIELDTERMINATOR = ''dc:stub:ft'',
ROWTERMINATOR = ''dc:stub:rt'',
CODEPAGE = ''RAW''
);
';
EXECUTE sp_executesql @stmt_bulkinsert;
DECLARE @bytesLoaded int
SELECT @bytesLoaded = ISNULL (DATALENGTH ([packagexml]), 0) FROM #bulkpackage
PRINT 'Loaded ' + CONVERT (varchar, @bytesLoaded)
+ ' bytes from '
+ '''' + REPLACE(@filename COLLATE database_default, N'''', N'''''') + ''''
DECLARE @packagebin varbinary(max);
SELECT @packagebin = convert(varbinary(max),[packagexml]) FROM #bulkpackage;
DECLARE @loadtime datetime;
SET @loadtime = getdate();
DROP TABLE #bulkpackage
EXECUTE sp_ssis_putpackage
@name = @packagename
, @id = @packageid
, @description = N'System Data Collector Package'
, @createdate = @loadtime
, @folderid = '8877FE4B-A938-4a51-84B9-C5BDAD74B0AD'
, @packagedata = @packagebin
, @packageformat = 1
, @packagetype = 5 -- DTSPKT_DTSDESIGNER100
, @vermajor = 1
, @verminor = 0
, @verbuild = 0
, @vercomments = N''
, @verid = @versionid
;
END;
GO
CREATE PROCEDURE #syscollector_upload_package
@packagename sysname,
@packageid uniqueidentifier,
@versionid uniqueidentifier
AS
BEGIN
DECLARE @installpath nvarchar(2048);
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\MSSQLServer\Setup', N'SQLPath', @installpath OUTPUT;
IF RIGHT(@installpath,1) != N'\' set @installpath = @installpath + N'\'
SET @installpath = @installpath + N'Install\'
DECLARE @filename nvarchar(2048);
SET @filename = @installpath + @packagename + N'.dtsx'
RAISERROR ('Uploading data collector package from disk: %s', 0, 1, @filename) WITH NOWAIT;
EXEC #syscollector_upload_package_from_file @filename=@filename, @packagename=@packagename, @packageid=@packageid, @versionid=@versionid;
END;
GO
--
-- Data Collector placeholder comment, dont move or remove.
-- 875f7de1-9e83-4be1-8b96-2df4a8533e88
--
-- Load SSIS packages needed by collector types
-- Temporarily enable the 'Agent XPs' config option so that sp_ssis_putpackage can
-- succeed when SQLAgent is stopped.
EXECUTE #syscollector_upload_package
@packagename='SqlTraceCollect'
, @packageid='0E149FC9-1046-4DE6-98BF-4B22ED6F6C42'
, @versionid='244F0904-5CC6-49B8-AE90-905AEEA8BAF3';
EXECUTE #syscollector_upload_package
@packagename='SqlTraceUpload'
, @packageid='F389A8E6-5A17-4056-ABFD-C8B823F2092E'
, @versionid='2D32AB4C-9929-4A85-A94E-7A01D8F40016';
EXECUTE #syscollector_upload_package
@packagename='TSQLQueryCollect'
, @packageid='292B1476-0F46-4490-A9B7-6DB724DE3C0B'
, @versionid='E24C6D00-94C6-457B-BED4-1F9F018F3273';
EXECUTE #syscollector_upload_package
@packagename='TSQLQueryUpload'
, @packageid='6EB73801-39CF-489C-B682-497350C939F0'
, @versionid='DA1210BC-C31B-43C6-B255-D8DDEB288CA1';
EXECUTE #syscollector_upload_package
@packagename='PerfCountersCollect'
, @packageid='C2EAABC1-5BF3-4127-BEB3-26E94D026E7D'
, @versionid='09A5B959-21B3-44E1-A37F-4A62BE5D6244';
EXECUTE #syscollector_upload_package
@packagename='PerfCountersUpload'
, @packageid='08D854CB-0D45-4E96-92C6-227A5DCD7066'
, @versionid='22A676DD-2025-493A-AD6B-C0186ABD556F';
EXECUTE #syscollector_upload_package
@packagename='QueryActivityCollect'
, @packageid='0B68FC9D-23DC-48F3-A937-90A0A8943D0E'
, @versionid='75A3A143-2059-433B-A11C-C8E0C80A83CF';
EXECUTE #syscollector_upload_package
@packagename='QueryActivityUpload'
, @packageid='833DB628-8E19-47A3-92C5-FB1779B52E76'
, @versionid='B1D79132-C6E6-46AA-8B14-E0AE4C4BA7BB';
GO
-- Cleanup the temp stored proc that we used to upload the SSIS packages
DROP PROCEDURE #syscollector_upload_package_from_file
DROP PROCEDURE #syscollector_upload_package
GO
---------------------------------------------------------------
-- Out-of-the-box collector type objects - definition for types
---------------------------------------------------------------
PRINT 'Creating or updating Collection Types...'
GO
-- Performance counters collector type
DECLARE @collector_type_uid uniqueidentifier
DECLARE @name sysname
DECLARE @parameter_schema xml
DECLARE @parameter_formatter xml
DECLARE @collection_package_id uniqueidentifier
DECLARE @upload_package_id uniqueidentifier
SET @collector_type_uid = '294605dd-21de-40b2-b20f-f3e170ea1ec3'
SET @name = 'Performance Counters Collector Type'
SET @parameter_schema =
'<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="DataCollectorType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="PerformanceCountersCollector">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="PerformanceCounters">
<xs:complexType>
<xs:attribute name="Objects" type="xs:string" use="required" />
<xs:attribute name="Counters" type="xs:string" use="required" />
<xs:attribute name="Instances" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="StoreLocalizedCounterNames" type="xs:boolean" use="optional" default="false" />
</xs:complexType>
</xs:element>
</xs:schema>
'
SET @parameter_formatter =
N'<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:z="#RowsetSchema"
>
<xsl:template match="/PerformanceCountersCollector">
<HTML>
<HEAD>
<TITLE></TITLE>
</HEAD>
<BODY>
<UL>
<xsl:apply-templates select="PerformanceCounters"/>
</UL>
<HR/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="PerformanceCounters">
<LI>
\<xsl:value-of select="@Objects"/>
<xsl:if test="@Instances">(<xsl:value-of select="@Instances"/>)</xsl:if>
\<xsl:value-of select="@Counters"/>
</LI>
</xsl:template>
</xsl:stylesheet>'
SET @collection_package_id = 'C2EAABC1-5BF3-4127-BEB3-26E94D026E7D'
SET @upload_package_id = '08D854CB-0D45-4E96-92C6-227A5DCD7066'
IF(EXISTS (SELECT * FROM dbo.syscollector_collector_types
WHERE collector_type_uid = @collector_type_uid))
BEGIN
PRINT 'Updating Performance counters collector type'
EXEC sp_syscollector_update_collector_type
@collector_type_uid = @collector_type_uid,
@name = @name,
@parameter_schema = @parameter_schema,
@parameter_formatter = @parameter_formatter,
@collection_package_id = @collection_package_id,
@upload_package_id = @upload_package_id
END
ELSE
BEGIN
PRINT 'Creating Performance Counters collector type'
EXEC sp_syscollector_create_collector_type
@collector_type_uid = @collector_type_uid,
@name = @name,
@parameter_schema = @parameter_schema,
@parameter_formatter = @parameter_formatter,
@collection_package_id = @collection_package_id,
@upload_package_id = @upload_package_id
END
UPDATE syscollector_collector_types
SET is_system = 1
WHERE collector_type_uid = @collector_type_uid
GO
-- TSQL query collector type
DECLARE @collector_type_uid uniqueidentifier
DECLARE @name sysname
DECLARE @parameter_schema xml
DECLARE @parameter_formatter xml
DECLARE @collection_package_id uniqueidentifier
DECLARE @upload_package_id uniqueidentifier
SET @collector_type_uid = '302E93D1-3424-4be7-AA8E-84813ECF2419'
SET @name = 'Generic T-SQL Query Collector Type'
SET @parameter_schema = '<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="DataCollectorType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="TSQLQueryCollector">
<xs:complexType>
<xs:sequence>
<xs:element name="Query" minOccurs="1" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Value" type="xs:string" />
<xs:element name="OutputTable" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Databases" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="Database" minOccurs="0" maxOccurs="unbounded" type="xs:string" />
</xs:sequence>
<xs:attribute name="UseSystemDatabases" type="xs:boolean" use="optional" />
<xs:attribute name="UseUserDatabases" type="xs:boolean" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>'
SET @parameter_formatter =
N'<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:z="#RowsetSchema"
>
<xsl:template match="/TSQLQueryCollector">
<HTML>
<HEAD>
<TITLE></TITLE>
</HEAD>
<BODY>
<xsl:apply-templates select="Query"/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="Query">
<I>
<xsl:value-of select="OutputTable"/>
</I> <BR/>
<PRE>
<xsl:value-of select="Value"/>
</PRE>
<HR/>
</xsl:template>
</xsl:stylesheet>'
SET @collection_package_id = '292B1476-0F46-4490-A9B7-6DB724DE3C0B'
SET @upload_package_id = '6EB73801-39CF-489C-B682-497350C939F0'
IF(EXISTS (SELECT * FROM dbo.syscollector_collector_types
WHERE collector_type_uid = @collector_type_uid))
BEGIN
PRINT 'Updating TSQL Query collector type'
EXEC sp_syscollector_update_collector_type
@collector_type_uid = @collector_type_uid,
@name = @name,
@parameter_schema = @parameter_schema,
@parameter_formatter = @parameter_formatter,
@collection_package_id = @collection_package_id,
@upload_package_id = @upload_package_id
END
ELSE
BEGIN
PRINT 'Creating T-SQL Query collector type'
EXEC sp_syscollector_create_collector_type
@collector_type_uid = @collector_type_uid,
@name = @name,
@parameter_schema = @parameter_schema,
@parameter_formatter = @parameter_formatter,
@collection_package_id = @collection_package_id,
@upload_package_id = @upload_package_id
END
-- mark the collector type as system
UPDATE syscollector_collector_types
SET is_system = 1
WHERE collector_type_uid = @collector_type_uid
GO
---------------------------------------------------------------
-- Database objects for TSQL query collector type
---------------------------------------------------------------
IF (OBJECT_ID(N'[dbo].[syscollector_tsql_query_collector]', 'U') IS NULL)
BEGIN
PRINT 'Creating table [dbo].[syscollector_tsql_query_collector]...'
CREATE TABLE [dbo].[syscollector_tsql_query_collector] (
collection_set_uid uniqueidentifier NOT NULL,
collection_set_id int NOT NULL,
collection_item_id int NOT NULL,
collection_package_id uniqueidentifier NOT NULL,
upload_package_id uniqueidentifier NOT NULL,
)
ALTER TABLE syscollector_tsql_query_collector
ADD CONSTRAINT [FK_syscollector_tsql_query_collector_syscollector_collection_items_internal] FOREIGN KEY(collection_set_id, collection_item_id)
REFERENCES syscollector_collection_items_internal (collection_set_id, collection_item_id) ON DELETE CASCADE
END
GO
IF (OBJECT_ID('dbo.syscollector_collection_item_parameter_update_trigger', 'TR') IS NOT NULL)
BEGIN
PRINT 'Dropping trigger [dbo].[syscollector_collection_item_parameter_update_trigger] on [dbo].[syscollector_collection_items_internal]'
DROP TRIGGER [dbo].[syscollector_collection_item_parameter_update_trigger]
END
GO
PRINT 'Creating trigger [dbo].[syscollector_collection_item_parameter_update_trigger] on [dbo].[syscollector_collection_items_internal]'
GO
CREATE TRIGGER [dbo].[syscollector_collection_item_parameter_update_trigger] on [dbo].[syscollector_collection_items_internal]
FOR UPDATE
AS
BEGIN
DECLARE @collection_set_id int
DECLARE @collection_item_id int
-- remove the TSQL query collection item that was updated so packages will be regenerated
-- base on the new parameters
IF (NOT UPDATE (parameters))
RETURN
-- clean up the SSIS packages that are left behind
DECLARE inserted_cursor CURSOR LOCAL FOR
SELECT collection_set_id, collection_item_id
FROM inserted
OPEN inserted_cursor
FETCH inserted_cursor INTO @collection_set_id, @collection_item_id
WHILE @@FETCH_STATUS = 0
BEGIN
DELETE FROM dbo.syscollector_tsql_query_collector
WHERE collection_set_id = @collection_set_id
AND collection_item_id = @collection_item_id
FETCH inserted_cursor INTO @collection_set_id, @collection_item_id
END
CLOSE inserted_cursor
DEALLOCATE inserted_cursor
END
GO
IF (OBJECT_ID('dbo.syscollector_tsql_query_collector_delete_trigger', 'TR') IS NOT NULL)
BEGIN
PRINT 'Dropping trigger [dbo].[syscollector_tsql_query_collector_delete_trigger] on [dbo].[syscollector_tsql_query_collector]'
DROP TRIGGER [dbo].[syscollector_tsql_query_collector_delete_trigger]
END
GO
PRINT 'Creating trigger [dbo].[syscollector_tsql_query_collector_delete_trigger] on [dbo].[syscollector_tsql_query_collector]'
GO
CREATE TRIGGER [dbo].[syscollector_tsql_query_collector_delete_trigger] on [dbo].[syscollector_tsql_query_collector]
FOR DELETE
AS
BEGIN
-- remove the SSIS packages left behind when the collection item is deleted
DECLARE @collection_package_id uniqueidentifier
DECLARE @collection_package_folderid uniqueidentifier
DECLARE @collection_package_name sysname
DECLARE @upload_package_id uniqueidentifier
DECLARE @upload_package_folderid uniqueidentifier
DECLARE @upload_package_name sysname
DECLARE deleted_cursor CURSOR LOCAL FOR
SELECT collection_package_id, upload_package_id
FROM deleted
OPEN deleted_cursor
FETCH deleted_cursor INTO @collection_package_id, @upload_package_id
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT
@collection_package_name = name,
@collection_package_folderid = folderid
FROM sysssispackages
WHERE @collection_package_id = id
SELECT
@upload_package_name = name,
@upload_package_folderid = folderid
FROM sysssispackages
WHERE @upload_package_id = id
EXEC dbo.sp_ssis_deletepackage
@name = @collection_package_name,
@folderid = @collection_package_folderid
EXEC dbo.sp_ssis_deletepackage
@name = @upload_package_name,
@folderid = @upload_package_folderid
FETCH deleted_cursor INTO @collection_package_id, @upload_package_id
END
CLOSE deleted_cursor
DEALLOCATE deleted_cursor
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_create_tsql_query_collector]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_create_tsql_query_collector]...'
DROP PROCEDURE [dbo].[sp_syscollector_create_tsql_query_collector]
END
GO
PRINT 'Creating procedure [dbo].[sp_syscollector_create_tsql_query_collector]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_create_tsql_query_collector]
@collection_set_uid uniqueidentifier,
@collection_item_id int,
@collection_package_id uniqueidentifier,
@upload_package_id uniqueidentifier
AS
BEGIN
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND
NOT (ISNULL(IS_MEMBER(N'dc_proxy'), 0) = 1) AND
NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_operator'' or ''dc_proxy')
RETURN(1) -- Failure
END
DECLARE @errMsg VARCHAR(256)
DECLARE @collection_set_id int
SELECT @collection_set_id = s.collection_set_id
FROM dbo.syscollector_collection_items i, dbo.syscollector_collection_sets s
WHERE i.collection_item_id = @collection_item_id
AND i.collector_type_uid = '302E93D1-3424-4be7-AA8E-84813ECF2419'
AND s.collection_set_uid = @collection_set_uid
-- Verify that the collection item exists of the correct type
IF (@collection_set_id IS NULL)
BEGIN
SELECT @errMsg = CONVERT(VARCHAR(36), @collection_set_uid) + ', ' + CONVERT(VARCHAR(36), @collection_item_id)
RAISERROR(14262, -1, -1, '@collection_set_uid, @collection_item_id', @errMsg)
RETURN(1)
END
-- Get the names and folder ids for the generated packages
DECLARE @upload_package_name sysname
DECLARE @upload_package_folder_id uniqueidentifier
SELECT @upload_package_name = name, @upload_package_folder_id = folderid
FROM sysssispackages
WHERE id = @upload_package_id
IF (@upload_package_name IS NULL)
BEGIN
SELECT @errMsg = @upload_package_name + ', ' + CONVERT(VARCHAR(36), @upload_package_folder_id)
RAISERROR(14262, -1, -1, '@upload_package_name, @upload_package_folder_id', @errMsg)
RETURN(1)
END
DECLARE @collection_package_name sysname
DECLARE @collection_package_folder_id uniqueidentifier
SELECT @collection_package_name = name, @collection_package_folder_id = folderid
FROM sysssispackages
WHERE id = @collection_package_id
IF (@collection_package_name IS NULL)
BEGIN
SELECT @errMsg = @collection_package_name + ', ' + CONVERT(VARCHAR(36), @collection_package_folder_id)
RAISERROR(14262, -1, -1, '@collection_package_name, @collection_package_folder_id', @errMsg)
RETURN(1)
END
-- we need to allow dc_admin to delete these packages along with the collection set when
-- the set is deleted
EXEC sp_ssis_setpackageroles @name = @upload_package_name, @folderid = @upload_package_folder_id, @readrole = NULL, @writerole = N'dc_admin'
EXEC sp_ssis_setpackageroles @name = @collection_package_name, @folderid = @collection_package_folder_id, @readrole = NULL, @writerole = N'dc_admin'
INSERT INTO [dbo].[syscollector_tsql_query_collector]
(
collection_set_uid,
collection_set_id,
collection_item_id,
collection_package_id,
upload_package_id
)
VALUES
(
@collection_set_uid,
@collection_set_id,
@collection_item_id,
@collection_package_id,
@upload_package_id
)
END
GO
IF (NOT OBJECT_ID('[dbo].[sp_syscollector_get_tsql_query_collector_package_ids]', 'P') IS NULL)
BEGIN
PRINT 'Dropping procedure [dbo].[sp_syscollector_get_tsql_query_collector_package_ids]...'
DROP PROCEDURE [dbo].[sp_syscollector_get_tsql_query_collector_package_ids]
END
GO
-- get and return the collection and upload package IDs
-- if they do not exist, return empty IDs
PRINT 'Creating procedure [dbo].[sp_syscollector_get_tsql_query_collector_package_ids]...'
GO
CREATE PROCEDURE [dbo].[sp_syscollector_get_tsql_query_collector_package_ids]
@collection_set_uid uniqueidentifier,
@collection_item_id int,
@collection_package_id uniqueidentifier OUTPUT,
@upload_package_id uniqueidentifier OUTPUT,
@collection_package_name sysname OUTPUT,
@upload_package_name sysname OUTPUT
AS
BEGIN
-- Security check (role membership)
IF (NOT (ISNULL(IS_MEMBER(N'dc_operator'), 0) = 1) AND
NOT (ISNULL(IS_MEMBER(N'dc_proxy'), 0) = 1) AND
NOT (ISNULL(IS_MEMBER(N'db_owner'), 0) = 1))
BEGIN
RAISERROR(14677, -1, -1, 'dc_operator'' or ''dc_proxy')
RETURN(1) -- Failure
END
SELECT @collection_package_id = collection_package_id,
@upload_package_id = upload_package_id
FROM dbo.syscollector_tsql_query_collector
WHERE @collection_item_id = collection_item_id
AND @collection_set_uid = collection_set_uid
IF(@collection_package_id IS NOT NULL AND @upload_package_id IS NOT NULL)
BEGIN
SELECT @collection_package_name = name
FROM dbo.sysssispackages
WHERE @collection_package_id = id
SELECT @upload_package_name = name
FROM dbo.sysssispackages
WHERE @upload_package_id = id
END
END
GO
--
-- This stored procedure is used to cleanup all activities done while configuring Data collector
-- Followign cleanup tasks are done
-- a) Delete collect, upload jobs
-- b) Set Data collector to non-configured state
-- c) Delete all collection set logs
--
IF (NOT OBJECT_ID(N'[dbo].[sp_syscollector_cleanup_collector]', 'P') IS NULL)
BEGIN
RAISERROR('Dropping procedure [dbo].[sp_syscollector_cleanup_collector] ...', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_syscollector_cleanup_collector]
END
GO
RAISERROR('Creating procedure [dbo].[sp_syscollector_cleanup_collector] ...', 0, 1) WITH NOWAIT;
GO
CREATE PROC [dbo].[sp_syscollector_cleanup_collector]
AS
BEGIN
-- Disable constraints
-- this is done to make sure that constraint logic does not interfere with cleanup process
ALTER TABLE dbo.syscollector_collection_sets_internal NOCHECK CONSTRAINT FK_syscollector_collection_sets_collection_sysjobs
ALTER TABLE dbo.syscollector_collection_sets_internal NOCHECK CONSTRAINT FK_syscollector_collection_sets_upload_sysjobs
-- Delete data collector jobs
DECLARE @job_id uniqueidentifier
DECLARE datacollector_jobs_cursor CURSOR LOCAL
FOR
SELECT collection_job_id AS job_id FROM syscollector_collection_sets
WHERE collection_job_id IS NOT NULL
UNION
SELECT upload_job_id AS job_id FROM syscollector_collection_sets
WHERE upload_job_id IS NOT NULL
OPEN datacollector_jobs_cursor
FETCH NEXT FROM datacollector_jobs_cursor INTO @job_id
WHILE (@@fetch_status = 0)
BEGIN
IF EXISTS ( SELECT COUNT(job_id) FROM sysjobs WHERE job_id = @job_id )
BEGIN
DECLARE @job_name sysname
SELECT @job_name = name from sysjobs WHERE job_id = @job_id
PRINT 'Removing job '+ @job_name
EXEC dbo.sp_delete_job @job_id=@job_id, @delete_unused_schedule=0
END
FETCH NEXT FROM datacollector_jobs_cursor INTO @job_id
END
CLOSE datacollector_jobs_cursor
DEALLOCATE datacollector_jobs_cursor
-- Enable Constraints back
ALTER TABLE dbo.syscollector_collection_sets_internal CHECK CONSTRAINT FK_syscollector_collection_sets_collection_sysjobs
ALTER TABLE dbo.syscollector_collection_sets_internal CHECK CONSTRAINT FK_syscollector_collection_sets_upload_sysjobs
-- Disable trigger on syscollector_collection_sets_internal
-- this is done to make sure that trigger logic does not interfere with cleanup process
EXEC('DISABLE TRIGGER syscollector_collection_set_is_running_update_trigger ON syscollector_collection_sets_internal')
-- Set collection sets as not running state
UPDATE syscollector_collection_sets_internal
SET is_running = 0
-- Update collect and upload jobs as null
UPDATE syscollector_collection_sets_internal
SET collection_job_id = NULL, upload_job_id = NULL
-- Enable back trigger on syscollector_collection_sets_internal
EXEC('ENABLE TRIGGER syscollector_collection_set_is_running_update_trigger ON syscollector_collection_sets_internal')
-- re-set collector config store
UPDATE syscollector_config_store_internal
SET parameter_value = 0
WHERE parameter_name IN ('CollectorEnabled')
UPDATE syscollector_config_store_internal
SET parameter_value = NULL
WHERE parameter_name IN ( 'MDWDatabase', 'MDWInstance' )
-- Delete collection set logs
DELETE FROM syscollector_execution_log_internal
END
GO
-- SQLTrace collector type
DECLARE @collector_type_uid uniqueidentifier
DECLARE @name sysname
DECLARE @parameter_schema xml
DECLARE @parameter_formatter xml
DECLARE @collection_package_id uniqueidentifier
DECLARE @upload_package_id uniqueidentifier
SET @collector_type_uid = '0E218CF8-ECB5-417B-B533-D851C0251271'
SET @name = 'Generic SQL Trace Collector Type'
SET @parameter_schema = '<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="DataCollectorType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="SqlTraceCollector">
<xs:complexType>
<xs:sequence>
<xs:element name="Events">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="EventType">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Event">
<xs:complexType>
<xs:attribute name="id" type="xs:unsignedByte" use="required" />
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="columnslist" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="id" type="xs:unsignedByte" use="optional" />
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Filters">
<xs:complexType>
<xs:sequence>
<xs:element name="Filter" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="columnid" type="xs:unsignedByte" use="required" />
<xs:attribute name="columnname" type="xs:string" use="required" />
<xs:attribute name="logical_operator" type="xs:string" use="required" />
<xs:attribute name="comparison_operator" type="xs:string" use="required" />
<xs:attribute name="value" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="use_default" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:schema>'
SET @parameter_formatter =
N'<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:z="#RowsetSchema"
>
<xsl:template match="/SqlTraceCollector">
<HTML>
<HEAD>
<TITLE></TITLE>
</HEAD>
<BODY>
<xsl:apply-templates select="Events"/>
<HR/>
<xsl:apply-templates select="Filters"/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="Events">
<xsl:apply-templates select="EventType"/>
<BR/>
</xsl:template>
<xsl:template match="EventType">
<I> <PRE> ID = <xsl:value-of select="@id"/> - <xsl:value-of select="@name"/> </PRE> </I>
<UL>
<xsl:apply-templates select="Event"/>
</UL>
</xsl:template>
<xsl:template match="Event">
<LI>
<PRE> ID = <xsl:value-of select="@id"/> - <xsl:value-of select="@name"/> </PRE>
</LI>
</xsl:template>
<xsl:template match="Filters">
<UL>
<xsl:apply-templates select="Filter" />
</UL>
</xsl:template>
<xsl:template match="Filter">
<PRE> <xsl:value-of select="@logical_operator"/> - <xsl:value-of select="@columnname"/> - <xsl:value-of select="@comparison_operator"/> - <xsl:value-of select="@value"/> </PRE>
</xsl:template>
</xsl:stylesheet>'
SET @collection_package_id = '0E149FC9-1046-4DE6-98BF-4B22ED6F6C42'
SET @upload_package_id = 'F389A8E6-5A17-4056-ABFD-C8B823F2092E'
IF(EXISTS (SELECT * FROM dbo.syscollector_collector_types
WHERE collector_type_uid = @collector_type_uid))
BEGIN
PRINT 'Updating SQL Trace collector type'
EXEC sp_syscollector_update_collector_type
@collector_type_uid = @collector_type_uid,
@name = @name,
@parameter_schema = @parameter_schema,
@parameter_formatter = @parameter_formatter,
@collection_package_id = @collection_package_id,
@upload_package_id = @upload_package_id
END
ELSE
BEGIN
PRINT 'Creating SQL Trace collector type'
EXEC sp_syscollector_create_collector_type
@collector_type_uid = @collector_type_uid,
@name = @name,
@parameter_schema = @parameter_schema,
@parameter_formatter = @parameter_formatter,
@collection_package_id = @collection_package_id,
@upload_package_id = @upload_package_id
END
-- mark the collector type as system
UPDATE syscollector_collector_types
SET is_system = 1
WHERE collector_type_uid = @collector_type_uid
GO
-- Query Activity Collector Type
DECLARE @collector_type_uid uniqueidentifier
DECLARE @name sysname
DECLARE @collection_package_id uniqueidentifier
DECLARE @upload_package_id uniqueidentifier
SET @collector_type_uid = '14AF3C12-38E6-4155-BD29-F33E7966BA23'
SET @name = 'Query Activity Collector Type'
SET @collection_package_id = '0B68FC9D-23DC-48F3-A937-90A0A8943D0E'
SET @upload_package_id = '833DB628-8E19-47A3-92C5-FB1779B52E76'
IF(EXISTS (SELECT * FROM dbo.syscollector_collector_types
WHERE collector_type_uid = @collector_type_uid))
BEGIN
PRINT 'Updating Query Activity Collector Type'
EXEC sp_syscollector_update_collector_type
@collector_type_uid = @collector_type_uid,
@name = @name,
@parameter_schema = NULL,
@parameter_formatter = NULL,
@collection_package_id = @collection_package_id,
@upload_package_id = @upload_package_id
END
ELSE
BEGIN
PRINT 'Creating Query Activity Collector Type'
EXEC sp_syscollector_create_collector_type
@collector_type_uid = @collector_type_uid,
@name = @name,
@parameter_schema = NULL,
@parameter_formatter = NULL,
@collection_package_id = @collection_package_id,
@upload_package_id = @upload_package_id
END
-- mark the collector type as system
UPDATE syscollector_collector_types
SET is_system = 1
WHERE collector_type_uid = @collector_type_uid
GO
---------------------------------------------------------------
-- Out-of-the-box collector objects - Generic schedules for system collection sets
---------------------------------------------------------------
PRINT 'Creating data collector schedules'
DECLARE @schedule_name sysname
SET @schedule_name = N'CollectorSchedule_Every_5min'
IF NOT EXISTS (SELECT name FROM msdb.dbo.sysschedules_localserver_view WHERE name = @schedule_name)
BEGIN
EXEC dbo.sp_add_schedule
@schedule_name = @schedule_name, -- Schedule name
@freq_type = 4, -- Daily
@freq_interval = 1, -- Recurs every 1 day
@freq_subday_type = 0x4, -- Frequency type is "minutes"
@freq_subday_interval = 5 -- Occurs every 5 minutes
END
SET @schedule_name = N'CollectorSchedule_Every_10min'
IF NOT EXISTS (SELECT name FROM msdb.dbo.sysschedules_localserver_view WHERE name = @schedule_name)
BEGIN
EXEC dbo.sp_add_schedule
@schedule_name = @schedule_name, -- Schedule name
@freq_type = 4, -- Daily
@freq_interval = 1, -- Recurs every 1 day
@freq_subday_type = 0x4, -- Frequency type is "minutes"
@freq_subday_interval = 10 -- Occurs every 10 minutes
END
SET @schedule_name = N'CollectorSchedule_Every_15min'
IF NOT EXISTS (SELECT name FROM msdb.dbo.sysschedules_localserver_view WHERE name = @schedule_name)
BEGIN
EXEC dbo.sp_add_schedule
@schedule_name = @schedule_name, -- Schedule name
@freq_type = 4, -- Daily
@freq_interval = 1, -- Recurs every 1 day
@freq_subday_type = 0x4, -- Frequency type is "minutes"
@freq_subday_interval = 15 -- Occurs every 15 minutes
END
SET @schedule_name = N'CollectorSchedule_Every_30min'
IF NOT EXISTS (SELECT name FROM msdb.dbo.sysschedules_localserver_view WHERE name = @schedule_name)
BEGIN
EXEC dbo.sp_add_schedule
@schedule_name = @schedule_name, -- Schedule name
@freq_type = 4, -- Daily
@freq_interval = 1, -- Recurs every 1 day
@freq_subday_type = 0x4, -- Frequency type is "minutes"
@freq_subday_interval = 30 -- Occurs every 30 minutes
END
SET @schedule_name = N'CollectorSchedule_Every_60min'
IF NOT EXISTS (SELECT name FROM msdb.dbo.sysschedules_localserver_view WHERE name = @schedule_name)
BEGIN
EXEC dbo.sp_add_schedule
@schedule_name = @schedule_name, -- Schedule name
@freq_type = 4, -- Daily
@freq_interval = 1, -- Recurs every 1 day
@freq_subday_type = 0x4, -- Frequency type is "minutes"
@freq_subday_interval = 60 -- Occurs every 60 minutes
END
SET @schedule_name = N'CollectorSchedule_Every_6h'
IF NOT EXISTS (SELECT name FROM msdb.dbo.sysschedules_localserver_view WHERE name = @schedule_name)
BEGIN
EXEC dbo.sp_add_schedule
@schedule_name = @schedule_name, -- Schedule name
@freq_type = 4, -- Daily
@freq_interval = 1, -- Recurs every 1 day
@freq_subday_type = 0x8, -- Frequency type is "hours"
@freq_subday_interval = 6 -- Occurs every 6 hours
END
GO
---------------------------------------------------------------
-- Out-of-the-box system Collection Sets
---------------------------------------------------------------
PRINT 'Creating system Collection Sets...'
------------------------------------------------
-- System collection set: Disk Usage
------------------------------------------------
DECLARE @collection_set_name NVARCHAR(128);
DECLARE @description NVARCHAR(4000);
DECLARE @collection_set_id int;
DECLARE @collection_set_uid uniqueidentifier;
DECLARE @collection_mode smallint;
DECLARE @schedule_name sysname;
DECLARE @days_until_expiration smallint;
DECLARE @name_id int;
DECLARE @description_id int;
-- The GUID below identifies this collection set and is used to locate the data collected by this collection set.
-- The name and description retrived via FORMATMESSAGE will not be localized for the initial mkmastr build of msdb,
-- but that is OK; the public interface to collection set detils (syscollector_collection_sets) is a view that will
-- dynamically pull the correct localized strings via its own FORMATMESSAGE calls. We just need a unique string to
-- store in the table.
SET @name_id = 14701;
SET @description_id = 14700;
SET @collection_set_uid = N'7B191952-8ECF-4E12-AEB2-EF646EF79FEF';
SET @collection_mode = 1; -- Non-cached
SET @schedule_name = N'CollectorSchedule_Every_6h';
SET @days_until_expiration = 730;
SET @description = FORMATMESSAGE(@description_id);
SET @collection_set_name = ISNULL (FORMATMESSAGE(@name_id), 'Disk Usage');
IF EXISTS (SELECT * FROM dbo.syscollector_collection_sets_internal WHERE collection_set_uid = @collection_set_uid)
BEGIN
RAISERROR ('Updating system Collection Set "%s"...', 0, 1, @collection_set_name) WITH NOWAIT;
-- We are updating an existing collection set -- get its ID
SELECT @collection_set_id = collection_set_id
FROM syscollector_collection_sets
WHERE collection_set_uid = @collection_set_uid;
-- Temporarily clear the is_system flag so that we can modify the collection set definition
UPDATE syscollector_collection_sets
SET is_system = 0
WHERE collection_set_id = @collection_set_id
-- Don't override the current expiration period or schedule settings, since the user may have customized these
EXEC dbo.sp_syscollector_update_collection_set
@collection_set_id = @collection_set_id,
@new_name = @collection_set_name,
@schedule_name = @schedule_name, -- avoid mismatch in uid if schedule was deleted and recreated
@collection_mode = @collection_mode,
@logging_level = 0,
@description = @description;
END
ELSE
BEGIN
RAISERROR ('Creating system Collection Set "%s"...', 0, 1, @collection_set_name) WITH NOWAIT;
EXEC dbo.sp_syscollector_create_collection_set
@collection_set_uid = @collection_set_uid,
@name = @collection_set_name,
@schedule_name = @schedule_name,
@collection_mode = @collection_mode,
@days_until_expiration = @days_until_expiration,
@description = @description,
@logging_level = 0,
@collection_set_id = @collection_set_id OUTPUT;
END
-- for localization of collection set name and description
UPDATE syscollector_collection_sets_internal
SET name_id = @name_id, description_id = @description_id
WHERE collection_set_uid = @collection_set_uid;
-- Add collection items
DECLARE @collection_item_name NVARCHAR(128);
DECLARE @collection_item_old_name NVARCHAR(128);
DECLARE @collection_item_id int;
DECLARE @frequency int;
-- Item 1: disk_usage DMV query
DECLARE @parameters xml;
SELECT @parameters = convert(xml, N'<ns:TSQLQueryCollector xmlns:ns="DataCollectorType">
<Query>
<Value>
DECLARE @dbsize bigint
DECLARE @logsize bigint
DECLARE @ftsize bigint
DECLARE @reservedpages bigint
DECLARE @pages bigint
DECLARE @usedpages bigint
SELECT @dbsize = SUM(convert(bigint,case when type = 0 then size else 0 end))
,@logsize = SUM(convert(bigint,case when type = 1 then size else 0 end))
,@ftsize = SUM(convert(bigint,case when type = 4 then size else 0 end))
FROM sys.database_files
SELECT @reservedpages = SUM(a.total_pages)
,@usedpages = SUM(a.used_pages)
,@pages = SUM(CASE
WHEN it.internal_type IN (202,204) THEN 0
WHEN a.type != 1 THEN a.used_pages
WHEN p.index_id < 2 THEN a.data_pages
ELSE 0
END)
FROM sys.partitions p
JOIN sys.allocation_units a ON p.partition_id = a.container_id
LEFT JOIN sys.internal_tables it ON p.object_id = it.object_id
SELECT
@dbsize as ''dbsize'',
@logsize as ''logsize'',
@ftsize as ''ftsize'',
@reservedpages as ''reservedpages'',
@usedpages as ''usedpages'',
@pages as ''pages''
</Value>
<OutputTable>disk_usage</OutputTable>
</Query>
<Databases UseSystemDatabases="true" UseUserDatabases="true" />
</ns:TSQLQueryCollector>');
-- The name and description retrived via FORMATMESSAGE will not be localized for the initial mkmastr build of msdb,
-- but that is OK; the public interface to collection item detils (syscollector_collection_items) is a view that will
-- dynamically pull the correct localized strings via its own FORMATMESSAGE calls. We just need a unique string to
-- store in the table.
SET @name_id = 14702;
SET @collection_item_name = FORMATMESSAGE(@name_id);
SET @collection_item_old_name = 'Disk Usage - Data Files';
SET @frequency = 60; -- Ignored (this collection set uses non-cached collection mode)
IF ISNULL (@collection_item_name, '') = ''
BEGIN
SET @collection_item_name = @collection_item_old_name;
END;
SET @collection_item_id = NULL;
SELECT @collection_item_id = collection_item_id
FROM syscollector_collection_items_internal
WHERE collection_set_id = @collection_set_id
AND (name = @collection_item_name OR name = @collection_item_old_name);
IF (@collection_item_id IS NOT NULL)
BEGIN
RAISERROR ('Updating Collection Item "%s"...', 0, 1, @collection_item_name);
EXEC dbo.sp_syscollector_update_collection_item
@collection_item_id = @collection_item_id,
@new_name = @collection_item_name,
@frequency = @frequency,
@parameters = @parameters;
END
ELSE
BEGIN
RAISERROR ('Creating Collection Item "%s"...', 0, 1, @collection_item_name);
EXEC dbo.sp_syscollector_create_collection_item
@collection_set_id = @collection_set_id,
@collector_type_uid = N'302E93D1-3424-4BE7-AA8E-84813ECF2419',
@name = @collection_item_name,
@parameters = @parameters,
@frequency = @frequency,
@collection_item_id = @collection_item_id output;
END;
-- for localization of collection item name
UPDATE syscollector_collection_items_internal
SET name_id = @name_id
WHERE collection_item_id = @collection_item_id;
-- Item 2: log_usage DMV query
SELECT @parameters = convert(xml, N'<ns:TSQLQueryCollector xmlns:ns="DataCollectorType">
<Query>
<Value>
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE @tran_log_space_usage table(
database_name sysname
, log_size_mb float
, log_space_used float
, status int
);
INSERT INTO @tran_log_space_usage
EXEC(''DBCC SQLPERF (LOGSPACE) WITH NO_INFOMSGS'');
SELECT
database_name,
log_size_mb,
log_space_used,
status
FROM @tran_log_space_usage
</Value>
<OutputTable>log_usage</OutputTable>
</Query>
</ns:TSQLQueryCollector>');
-- The name and description retrived via FORMATMESSAGE will not be localized for the initial mkmastr build of msdb,
-- but that is OK; the public interface to collection item detils (syscollector_collection_items) is a view that will
-- dynamically pull the correct localized strings via its own FORMATMESSAGE calls. We just need a unique string to
-- store in the table.
SET @name_id = 14703;
SET @collection_item_name = FORMATMESSAGE(@name_id);
SET @collection_item_old_name = 'Disk Usage - Log Files';
SET @frequency = 60; -- Ignored (this collection set uses non-cached collection mode)
IF ISNULL (@collection_item_name, '') = ''
BEGIN
SET @collection_item_name = @collection_item_old_name;
END;
SET @collection_item_id = NULL;
SELECT @collection_item_id = collection_item_id
FROM syscollector_collection_items_internal
WHERE collection_set_id = @collection_set_id
AND (name = @collection_item_name OR name = @collection_item_old_name);
IF (@collection_item_id IS NOT NULL)
BEGIN
RAISERROR ('Updating Collection Item "%s"...', 0, 1, @collection_item_name);
EXEC dbo.sp_syscollector_update_collection_item
@collection_item_id = @collection_item_id,
@new_name = @collection_item_name,
@frequency = @frequency,
@parameters = @parameters;
END
ELSE
BEGIN
RAISERROR ('Creating Collection Item "%s"...', 0, 1, @collection_item_name);
EXEC dbo.sp_syscollector_create_collection_item
@collection_set_id = @collection_set_id,
@collector_type_uid = N'302E93D1-3424-4BE7-AA8E-84813ECF2419',
@name = @collection_item_name,
@parameters = @parameters,
@frequency = @frequency,
@collection_item_id = @collection_item_id output;
END;
-- for localization of collection item name
UPDATE syscollector_collection_items_internal
SET name_id = @name_id
WHERE collection_item_id = @collection_item_id;
-- Turn the is_system flag on so users can't change the definition of this collection set
UPDATE syscollector_collection_sets
SET is_system = 1
WHERE collection_set_id = @collection_set_id
GO
------------------------------------------------
-- System collection set: Server Activity
------------------------------------------------
DECLARE @collection_set_name NVARCHAR(128);
DECLARE @description NVARCHAR(4000);
DECLARE @collection_set_id int;
DECLARE @collection_set_uid uniqueidentifier;
DECLARE @collection_mode smallint;
DECLARE @schedule_name sysname;
DECLARE @days_until_expiration smallint;
DECLARE @name_id int;
DECLARE @description_id int;
-- The GUID below identifies this collection set and is used to locate the data collected by this collection set.
-- The name and description retrived via FORMATMESSAGE will not be localized for the initial mkmastr build of msdb,
-- but that is OK; the public interface to collection set detils (syscollector_collection_sets) is a view that will
-- dynamically pull the correct localized strings via its own FORMATMESSAGE calls. We just need a unique string to
-- store in the table.
SET @name_id = 14705;
SET @description_id = 14704;
SET @collection_set_uid = N'49268954-4FD4-4EB6-AA04-CD59D9BB5714';
SET @collection_mode = 0; -- Cached
SET @schedule_name = N'CollectorSchedule_Every_15min';
SET @days_until_expiration = 14;
SET @description = FORMATMESSAGE(@description_id);
SET @collection_set_name = ISNULL (FORMATMESSAGE(@name_id), 'Server Activity');
IF EXISTS (SELECT * FROM dbo.syscollector_collection_sets_internal WHERE collection_set_uid = @collection_set_uid)
BEGIN
RAISERROR ('Updating system Collection Set "%s"...', 0, 1, @collection_set_name) WITH NOWAIT;
-- We are updating an existing collection set -- get its ID
SELECT @collection_set_id = collection_set_id
FROM syscollector_collection_sets
WHERE collection_set_uid = @collection_set_uid;
-- Temporarily clear the is_system flag so that we can modify the collection set definition
UPDATE syscollector_collection_sets
SET is_system = 0
WHERE collection_set_id = @collection_set_id
-- Don't override the current expiration period or schedule settings, since the user may have customized these
EXEC dbo.sp_syscollector_update_collection_set
@collection_set_id = @collection_set_id,
@new_name = @collection_set_name,
@schedule_name = @schedule_name, -- avoid mismatch in uid if schedule was deleted and recreated
@collection_mode = @collection_mode,
@logging_level = 0,
@description = @description;
END
ELSE
BEGIN
RAISERROR ('Creating system Collection Set "%s"...', 0, 1, @collection_set_name) WITH NOWAIT;
EXEC dbo.sp_syscollector_create_collection_set
@collection_set_uid = @collection_set_uid,
@name = @collection_set_name,
@schedule_name = @schedule_name,
@collection_mode = @collection_mode,
@days_until_expiration = @days_until_expiration,
@description = @description,
@logging_level = 0,
@collection_set_id = @collection_set_id OUTPUT;
END
-- for localization of collection set name and description
UPDATE syscollector_collection_sets_internal
SET name_id = @name_id, description_id = @description_id
WHERE collection_set_uid = @collection_set_uid;
-- Add collection items
DECLARE @collection_item_name NVARCHAR(128);
DECLARE @collection_item_old_name NVARCHAR(128);
DECLARE @collection_item_id int;
DECLARE @frequency int;
DECLARE @parameters xml;
-- Item 1 - DMV SNAPSHOTS
SELECT @parameters = convert(xml, N'<ns:TSQLQueryCollector xmlns:ns="DataCollectorType">
<Query>
<Value>
SET NOCOUNT ON
SELECT
LEFT (wait_type, 45) AS wait_type,
SUM (waiting_tasks_count) AS waiting_tasks_count,
SUM (wait_time_ms) AS wait_time_ms,
SUM (signal_wait_time_ms) AS signal_wait_time_ms
FROM
(
SELECT
LEFT (wait_type, 45) AS wait_type,
waiting_tasks_count,
wait_time_ms,
signal_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE waiting_tasks_count > 0 OR wait_time_ms > 0 OR signal_wait_time_ms > 0
UNION ALL
SELECT
LEFT (wait_type, 45) AS wait_type,
1 AS waiting_tasks_count,
wait_duration_ms AS wait_time_ms,
0 AS signal_wait_time_ms
FROM sys.dm_os_waiting_tasks
WHERE wait_duration_ms > 60000
) AS merged_wait_stats
GROUP BY wait_type
</Value>
<OutputTable>os_wait_stats</OutputTable>
</Query>
<Query>
<Value>
SET NOCOUNT ON
SELECT
LEFT(latch_class,45) as latch_class,
waiting_requests_count,
wait_time_ms
FROM sys.dm_os_latch_stats
WHERE waiting_requests_count > 0 OR wait_time_ms > 0
</Value>
<OutputTable>os_latch_stats</OutputTable>
</Query>
<Query>
<Value>
SET NOCOUNT ON
SELECT
pm.physical_memory_in_use_kb AS sql_physical_memory_in_use_kb,
pm.large_page_allocations_kb AS sql_large_page_allocations_kb,
pm.locked_page_allocations_kb AS sql_locked_page_allocations_kb,
pm.total_virtual_address_space_kb AS sql_total_virtual_address_space_kb,
pm.virtual_address_space_reserved_kb AS sql_virtual_address_space_reserved_kb,
pm.virtual_address_space_committed_kb AS sql_virtual_address_space_committed_kb,
pm.virtual_address_space_available_kb AS sql_virtual_address_space_available_kb,
pm.page_fault_count AS sql_page_fault_count,
pm.memory_utilization_percentage AS sql_memory_utilization_percentage,
pm.available_commit_limit_kb AS sql_available_commit_limit_kb,
pm.process_physical_memory_low AS sql_process_physical_memory_low,
pm.process_virtual_memory_low AS sql_process_virtual_memory_low,
sm.total_physical_memory_kb AS system_total_physical_memory_kb,
sm.available_physical_memory_kb AS system_available_physical_memory_kb,
sm.total_page_file_kb AS system_total_page_file_kb,
sm.available_page_file_kb AS system_available_page_file_kb,
sm.system_cache_kb AS system_cache_kb,
sm.kernel_paged_pool_kb AS system_kernel_paged_pool_kb,
sm.kernel_nonpaged_pool_kb AS system_kernel_nonpaged_pool_kb,
sm.system_high_memory_signal_state AS system_high_memory_signal_state,
sm.system_low_memory_signal_state AS system_low_memory_signal_state,
-- Three columns were removed from the dm_os_sys_info DMV in SQL11 as part of a change
-- to memory manager architecture: bpool_committed, bpool_commit_target, and bpool_visible.
-- While it is no longer correct, strictly speaking, to speak of such things as "buffer
-- pool target" memory in SQL Server versions after SQL 2008 R2, in the MDW database these
-- values were simply used as a proxy for "SQL Server committed memory" and "SQL Server
-- target memory"; the fact that it used to be buffer pool but now is the memory mgr that
-- tracks these values is immaterial to how they are used in MDW. There are three new
-- columns that were added in versions after SQL 2008 R2; we map the new column that provides
-- comparable information to the old SQL 2008/2008 R2 column name. This allows the same MDW
-- schema to work with data from any supported version. The old DMV values were counts of
-- 8KB pages; the replacement columns provide a KB count.
(si.committed_target_kb / 8) AS bpool_commit_target,
(si.committed_kb / 8) AS bpool_committed,
(si.visible_target_kb / 8) AS bpool_visible
FROM sys.dm_os_process_memory AS pm
CROSS JOIN sys.dm_os_sys_memory AS sm -- single-row DMV
CROSS JOIN sys.dm_os_sys_info AS si; -- single-row DMV
</Value>
<OutputTable>sql_process_and_system_memory</OutputTable>
</Query>
<Query>
<Value>
SET NOCOUNT ON
SELECT
memory_node_id,
virtual_address_space_reserved_kb,
virtual_address_space_committed_kb,
locked_page_allocations_kb,
-- In SQL 2008 and 2008 R2, we collected the [single_pages_kb] and [multi_pages_kb] columns
-- from this DMV. In later versions, the memory manager has been changed so that the fundamental
-- distinction between single-page and multi-page allocations no longer exists. As a result,
-- these two columns were removed, and a "pages_kb" column was added instead. In the MDW
-- database, these two columns were just added together to calculate total memory allocated
-- by the memory node. We don''t want to remove these columns from the destination table since
-- that would break all SQL2008/2008R2 clients until they could be patched. So, to maximize
-- backwards compatibility and minimize the size of this change, we simply return the new
-- [pages_kb] value in the existing [single_pages_kb] column. This isn''t an entirely
-- accurate name for the value, but it doesn''t affect the way that this value is used after
-- it has been uploaded to MDW.
pages_kb AS single_pages_kb,
0 AS multi_pages_kb,
shared_memory_reserved_kb,
shared_memory_committed_kb
FROM sys.dm_os_memory_nodes
</Value>
<OutputTable>os_memory_nodes</OutputTable>
</Query>
<Query>
<Value>
SET NOCOUNT ON
SELECT
type,
memory_node_id as memory_node_id,
-- See comment in the sys.dm_os_memory_nodes query (above) for more info on
-- [single_pages_kb] and [multi_pages_kb].
SUM(pages_kb) as single_pages_kb,
0 as multi_pages_kb,
SUM(virtual_memory_reserved_kb) as virtual_memory_reserved_kb,
SUM(virtual_memory_committed_kb) as virtual_memory_committed_kb,
SUM(awe_allocated_kb) as awe_allocated_kb,
SUM(shared_memory_reserved_kb) as shared_memory_reserved_kb,
SUM(shared_memory_committed_kb) as shared_memory_committed_kb
FROM sys.dm_os_memory_clerks
GROUP BY type, memory_node_id</Value>
<OutputTable>os_memory_clerks</OutputTable>
</Query>
<Query>
<Value>
SET NOCOUNT ON
SELECT
[parent_node_id],
[scheduler_id],
[cpu_id],
[status],
[is_idle],
[preemptive_switches_count],
[context_switches_count],
[yield_count],
[current_tasks_count],
[runnable_tasks_count],
[work_queue_count],
[pending_disk_io_count]
FROM sys.dm_os_schedulers
WHERE scheduler_id < 128
</Value>
<OutputTable>os_schedulers</OutputTable>
</Query>
<Query>
<Value>
SELECT
DB_NAME (f.database_id) AS database_name, f.database_id, f.name AS logical_file_name, f.[file_id], f.type_desc,
CAST (CASE
-- Handle UNC paths (e.g. ''\\fileserver\readonlydbs\dept_dw.ndf'' --> ''\\fileserver\readonlydbs'')
WHEN LEFT (LTRIM (f.physical_name), 2) = ''\\''
THEN LEFT (LTRIM (f.physical_name), CHARINDEX (''\'', LTRIM (f.physical_name), CHARINDEX (''\'', LTRIM (f.physical_name), 3) + 1) - 1)
-- Handle local paths (e.g. ''C:\Program Files\...\master.mdf'' --> ''C:'')
WHEN CHARINDEX (''\'', LTRIM(f.physical_name), 3) > 0
THEN UPPER (LEFT (LTRIM (f.physical_name), CHARINDEX (''\'', LTRIM (f.physical_name), 3) - 1))
ELSE f.physical_name
END AS nvarchar(255)) AS logical_disk,
fs.num_of_reads, fs.num_of_bytes_read, fs.io_stall_read_ms, fs.num_of_writes, fs.num_of_bytes_written,
fs.io_stall_write_ms, fs.size_on_disk_bytes
FROM sys.dm_io_virtual_file_stats (default, default) AS fs
INNER JOIN sys.master_files AS f ON fs.database_id = f.database_id AND fs.[file_id] = f.[file_id]
</Value>
<OutputTable>io_virtual_file_stats</OutputTable>
</Query>
</ns:TSQLQueryCollector>');
-- The name and description retrived via FORMATMESSAGE will not be localized for the initial mkmastr build of msdb,
-- but that is OK; the public interface to collection item detils (syscollector_collection_items) is a view that will
-- dynamically pull the correct localized strings via its own FORMATMESSAGE calls. We just need a unique string to
-- store in the table.
SET @name_id = 14706;
SET @collection_item_name = FORMATMESSAGE(@name_id);
SET @collection_item_old_name = 'Server Activity - DMV Snapshots';
SET @frequency = 60;
IF ISNULL (@collection_item_name, '') = ''
BEGIN
SET @collection_item_name = @collection_item_old_name;
END;
SET @collection_item_id = NULL;
SELECT @collection_item_id = collection_item_id
FROM syscollector_collection_items_internal
WHERE collection_set_id = @collection_set_id
AND (name = @collection_item_name OR name = @collection_item_old_name);
IF (@collection_item_id IS NOT NULL)
BEGIN
RAISERROR ('Updating Collection Item "%s"...', 0, 1, @collection_item_name);
EXEC dbo.sp_syscollector_update_collection_item
@collection_item_id = @collection_item_id,
@new_name = @collection_item_name,
@frequency = @frequency,
@parameters = @parameters;
END
ELSE
BEGIN
RAISERROR ('Creating Collection Item "%s"...', 0, 1, @collection_item_name);
EXEC dbo.sp_syscollector_create_collection_item
@collection_set_id = @collection_set_id,
@collector_type_uid = N'302E93D1-3424-4BE7-AA8E-84813ECF2419',
@name = @collection_item_name,
@parameters = @parameters,
@frequency = @frequency,
@collection_item_id = @collection_item_id output;
END;
-- for localization of collection item name
UPDATE syscollector_collection_items_internal
SET name_id = @name_id
WHERE collection_item_id = @collection_item_id;
-- Item 2 - PERFORMANCE COUNTERS
SELECT @parameters = convert(xml, N'<ns:PerformanceCountersCollector xmlns:ns="DataCollectorType">
<PerformanceCounters Objects="Memory" Counters="% Committed Bytes In Use" />
<PerformanceCounters Objects="Memory" Counters="Available Bytes" />
<PerformanceCounters Objects="Memory" Counters="Cache Bytes" />
<PerformanceCounters Objects="Memory" Counters="Cache Faults/sec" />
<PerformanceCounters Objects="Memory" Counters="Committed Bytes" />
<PerformanceCounters Objects="Memory" Counters="Free & Zero Page List Bytes" />
<PerformanceCounters Objects="Memory" Counters="Modified Page List Bytes" />
<PerformanceCounters Objects="Memory" Counters="Pages/sec" />
<PerformanceCounters Objects="Memory" Counters="Page Reads/sec" />
<PerformanceCounters Objects="Memory" Counters="Page Write/sec" />
<PerformanceCounters Objects="Memory" Counters="Page Faults/sec" />
<PerformanceCounters Objects="Memory" Counters="Pool Nonpaged Bytes" />
<PerformanceCounters Objects="Memory" Counters="Pool Paged Bytes" />
<PerformanceCounters Objects="Memory" Counters="Standby Cache Core Bytes" />
<PerformanceCounters Objects="Memory" Counters="Standby Cache Normal Priority Bytes" />
<PerformanceCounters Objects="Memory" Counters="Standby Cache Reserve Bytes" />
<PerformanceCounters Objects="Memory" Counters="Pool Paged Bytes" />
<PerformanceCounters Objects="Memory" Counters="Write Copies/sec" />
<PerformanceCounters Objects="Process" Counters="*" Instances="_Total" />
<PerformanceCounters Objects="Process" Counters="*" Instances="$(TARGETPROCESS)" />
<PerformanceCounters Objects="Process" Counters="Thread Count" Instances="*" />
<PerformanceCounters Objects="Process" Counters="% Processor Time" Instances="*" />
<PerformanceCounters Objects="Process" Counters="IO Read Bytes/sec" Instances="*" />
<PerformanceCounters Objects="Process" Counters="IO Write Bytes/sec" Instances="*" />
<PerformanceCounters Objects="Process" Counters="Private Bytes" Instances="*" />
<PerformanceCounters Objects="Process" Counters="Working Set" Instances="*" />
<PerformanceCounters Objects="Processor" Counters="% Processor Time" Instances="*" />
<PerformanceCounters Objects="Processor" Counters="% User Time" Instances="*" />
<PerformanceCounters Objects="Processor" Counters="% Privileged Time" Instances="*" />
<PerformanceCounters Objects="Server Work Queues" Counters="Queue Length" Instances="*" />
<PerformanceCounters Objects="LogicalDisk" Counters="% Disk Time" Instances="*" />
<PerformanceCounters Objects="LogicalDisk" Counters="Avg. Disk Queue Length" Instances="*" />
<PerformanceCounters Objects="LogicalDisk" Counters="Avg. Disk Read Queue Length" Instances="*" />
<PerformanceCounters Objects="LogicalDisk" Counters="Avg. Disk Write Queue Length" Instances="*" />
<PerformanceCounters Objects="LogicalDisk" Counters="Avg. Disk sec/Read" Instances="*" />
<PerformanceCounters Objects="LogicalDisk" Counters="Avg. Disk sec/Write" Instances="*" />
<PerformanceCounters Objects="LogicalDisk" Counters="Avg. Disk sec/Transfer" Instances="*" />
<PerformanceCounters Objects="LogicalDisk" Counters="Disk Reads/sec" Instances="*" />
<PerformanceCounters Objects="LogicalDisk" Counters="Disk Bytes/sec" Instances="*" />
<PerformanceCounters Objects="LogicalDisk" Counters="Disk Writes/sec" Instances="*" />
<PerformanceCounters Objects="LogicalDisk" Counters="Split IO/sec" Instances="*" />
<PerformanceCounters Objects="System" Counters="Processor Queue Length" />
<PerformanceCounters Objects="System" Counters="File Read Operations/sec" />
<PerformanceCounters Objects="System" Counters="File Write Operations/sec" />
<PerformanceCounters Objects="System" Counters="File Control Operations/sec" />
<PerformanceCounters Objects="System" Counters="File Read Bytes/sec" />
<PerformanceCounters Objects="System" Counters="File Write Bytes/sec" />
<PerformanceCounters Objects="System" Counters="File Control Bytes/sec" />
<PerformanceCounters Objects="Network Interface" Counters="Bytes Total/sec" Instances="*" />
<PerformanceCounters Objects="Network Interface" Counters="Output Queue Length" Instances="*" />
<PerformanceCounters Objects="$(INSTANCE):Buffer Manager" Counters="Stolen pages"/>
<PerformanceCounters Objects="$(INSTANCE):Buffer Manager" Counters="Page life expectancy"/>
<PerformanceCounters Objects="$(INSTANCE):Memory Manager" Counters="Memory Grants Outstanding"/>
<PerformanceCounters Objects="$(INSTANCE):Memory Manager" Counters="Memory Grants Pending"/>
<PerformanceCounters Objects="$(INSTANCE):Databases" Counters="Transactions/sec" Instances="_Total"/>
<PerformanceCounters Objects="$(INSTANCE):Databases" Counters="Transactions/sec" Instances="tempdb"/>
<PerformanceCounters Objects="$(INSTANCE):Databases" Counters="Active Transactions" Instances="*"/>
<PerformanceCounters Objects="$(INSTANCE):General Statistics" Counters="Logins/sec" />
<PerformanceCounters Objects="$(INSTANCE):General Statistics" Counters="Logouts/sec" />
<PerformanceCounters Objects="$(INSTANCE):General Statistics" Counters="User Connections" />
<PerformanceCounters Objects="$(INSTANCE):General Statistics" Counters="Logical Connections" />
<PerformanceCounters Objects="$(INSTANCE):General Statistics" Counters="Transactions" />
<PerformanceCounters Objects="$(INSTANCE):General Statistics" Counters="Processes blocked" />
<PerformanceCounters Objects="$(INSTANCE):General Statistics" Counters="Active Temp Tables" />
<PerformanceCounters Objects="$(INSTANCE):SQL Statistics" Counters="Batch Requests/sec" />
<PerformanceCounters Objects="$(INSTANCE):SQL Statistics" Counters="SQL Compilations/sec" />
<PerformanceCounters Objects="$(INSTANCE):SQL Statistics" Counters="SQL Re-Compilations/sec" />
<PerformanceCounters Objects="$(INSTANCE):SQL Statistics" Counters="SQL Attention rate" />
<PerformanceCounters Objects="$(INSTANCE):SQL Statistics" Counters="Auto-Param Attempts/sec" />
<PerformanceCounters Objects="$(INSTANCE):SQL Statistics" Counters="Failed Auto-Params/sec" />
<PerformanceCounters Objects="$(INSTANCE):Plan Cache" Counters="Cache Hit Ratio" Instances="_Total" />
<PerformanceCounters Objects="$(INSTANCE):Plan Cache" Counters="Cache Hit Ratio" Instances="Object Plans" />
<PerformanceCounters Objects="$(INSTANCE):Plan Cache" Counters="Cache Hit Ratio" Instances="SQL Plans" />
<PerformanceCounters Objects="$(INSTANCE):Plan Cache" Counters="Cache Hit Ratio" Instances="Temporary Tables & Table Variables" />
<PerformanceCounters Objects="$(INSTANCE):Transactions" Counters="Free Space in tempdb (KB)"/>
<PerformanceCounters Objects="$(INSTANCE):Workload Group Stats" Counters="Active requests" Instances="*"/>
<PerformanceCounters Objects="$(INSTANCE):Workload Group Stats" Counters="Blocked tasks" Instances="*"/>
<PerformanceCounters Objects="$(INSTANCE):Workload Group Stats" Counters="CPU usage %" Instances="*"/>
</ns:PerformanceCountersCollector>');
-- The name and description retrived via FORMATMESSAGE will not be localized for the initial mkmastr build of msdb,
-- but that is OK; the public interface to collection item detils (syscollector_collection_items) is a view that will
-- dynamically pull the correct localized strings via its own FORMATMESSAGE calls. We just need a unique string to
-- store in the table.
SET @name_id = 14707;
SET @collection_item_name = FORMATMESSAGE(@name_id);
SET @collection_item_old_name = 'Server Activity - Performance Counters';
SET @frequency = 60;
IF ISNULL (@collection_item_name, '') = ''
BEGIN
SET @collection_item_name = @collection_item_old_name;
END;
SET @collection_item_id = NULL;
SELECT @collection_item_id = collection_item_id
FROM syscollector_collection_items_internal
WHERE collection_set_id = @collection_set_id
AND (name = @collection_item_name OR name = @collection_item_old_name);
IF (@collection_item_id IS NOT NULL)
BEGIN
RAISERROR ('Updating Collection Item "%s"...', 0, 1, @collection_item_name);
EXEC dbo.sp_syscollector_update_collection_item
@collection_item_id = @collection_item_id,
@new_name = @collection_item_name,
@frequency = @frequency,
@parameters = @parameters;
END
ELSE
BEGIN
RAISERROR ('Creating Collection Item "%s"...', 0, 1, @collection_item_name);
EXEC dbo.sp_syscollector_create_collection_item
@collection_set_id = @collection_set_id,
@collector_type_uid = N'294605DD-21DE-40B2-B20F-F3E170EA1EC3',
@name = @collection_item_name,
@parameters = @parameters,
@frequency = @frequency,
@collection_item_id = @collection_item_id output;
END;
-- for localization of collection item name
UPDATE syscollector_collection_items_internal
SET name_id = @name_id
WHERE collection_item_id = @collection_item_id;
-- Turn the is_system flag on so users can't change the definition of this collection set
UPDATE syscollector_collection_sets
SET is_system = 1
WHERE collection_set_id = @collection_set_id
GO
------------------------------------------------
-- System collection set: Query Statistics
------------------------------------------------
DECLARE @collection_set_name NVARCHAR(128);
DECLARE @description NVARCHAR(4000);
DECLARE @collection_set_id int;
DECLARE @collection_set_uid uniqueidentifier;
DECLARE @collection_mode smallint;
DECLARE @schedule_name sysname;
DECLARE @days_until_expiration smallint;
DECLARE @name_id int;
DECLARE @description_id int;
-- The GUID below identifies this collection set and is used to locate the data collected by this collection set.
-- The name and description retrived via FORMATMESSAGE will not be localized for the initial mkmastr build of msdb,
-- but that is OK; the public interface to collection set detils (syscollector_collection_sets) is a view that will
-- dynamically pull the correct localized strings via its own FORMATMESSAGE calls. We just need a unique string to
-- store in the table.
SET @name_id = 14709;
SET @description_id = 14708;
SET @collection_set_uid = N'2DC02BD6-E230-4C05-8516-4E8C0EF21F95';
SET @collection_mode = 0; -- Cached
SET @schedule_name = N'CollectorSchedule_Every_15min';
SET @days_until_expiration = 14;
SET @description = FORMATMESSAGE(@description_id);
SET @collection_set_name = ISNULL (FORMATMESSAGE(@name_id), 'Query Statistics');
IF EXISTS (SELECT * FROM dbo.syscollector_collection_sets_internal WHERE collection_set_uid = @collection_set_uid)
BEGIN
RAISERROR ('Updating system Collection Set "%s"...', 0, 1, @collection_set_name) WITH NOWAIT;
-- We are updating an existing collection set -- get its ID
SELECT @collection_set_id = collection_set_id
FROM syscollector_collection_sets
WHERE collection_set_uid = @collection_set_uid;
-- Temporarily clear the is_system flag so that we can modify the collection set definition
UPDATE syscollector_collection_sets
SET is_system = 0
WHERE collection_set_id = @collection_set_id
-- Don't override the current expiration period or schedule settings, since the user may have customized these
EXEC dbo.sp_syscollector_update_collection_set
@collection_set_id = @collection_set_id,
@new_name = @collection_set_name,
@schedule_name = @schedule_name, -- avoid mismatch in uid if schedule was deleted and recreated
@collection_mode = @collection_mode,
@logging_level = 0,
@description = @description;
END
ELSE
BEGIN
RAISERROR ('Creating system Collection Set "%s"...', 0, 1, @collection_set_name) WITH NOWAIT;
EXEC dbo.sp_syscollector_create_collection_set
@collection_set_uid = @collection_set_uid,
@name = @collection_set_name,
@schedule_name = @schedule_name,
@collection_mode = @collection_mode,
@days_until_expiration = @days_until_expiration,
@description = @description,
@logging_level = 0,
@collection_set_id = @collection_set_id OUTPUT;
END
-- for localization of collection set name and description
UPDATE syscollector_collection_sets_internal
SET name_id = @name_id, description_id = @description_id
WHERE collection_set_uid = @collection_set_uid;
-- Add collection items
DECLARE @collection_item_name NVARCHAR(128);
DECLARE @collection_item_old_name NVARCHAR(128);
DECLARE @collection_item_id int;
DECLARE @frequency int;
DECLARE @parameters xml;
-- Item 1 - Query activity collection type
-- The name and description retrived via FORMATMESSAGE will not be localized for the initial mkmastr build of msdb,
-- but that is OK; the public interface to collection item detils (syscollector_collection_items) is a view that will
-- dynamically pull the correct localized strings via its own FORMATMESSAGE calls. We just need a unique string to
-- store in the table.
SET @name_id = 14710;
SET @collection_item_name = FORMATMESSAGE(@name_id);
SET @collection_item_old_name = 'Query Statistics - Query Activity';
SET @frequency = 10;
IF ISNULL (@collection_item_name, '') = ''
BEGIN
SET @collection_item_name = @collection_item_old_name;
END;
SET @collection_item_id = NULL;
SELECT @collection_item_id = collection_item_id
FROM syscollector_collection_items_internal
WHERE collection_set_id = @collection_set_id
AND (name = @collection_item_name OR name = @collection_item_old_name);
IF (@collection_item_id IS NOT NULL)
BEGIN
RAISERROR ('Updating Collection Item "%s"...', 0, 1, @collection_item_name);
EXEC dbo.sp_syscollector_update_collection_item
@collection_item_id = @collection_item_id,
@new_name = @collection_item_name,
@frequency = @frequency,
@parameters = @parameters;
END
ELSE
BEGIN
RAISERROR ('Creating Collection Item "%s"...', 0, 1, @collection_item_name);
EXEC dbo.sp_syscollector_create_collection_item
@collection_set_id = @collection_set_id,
@collector_type_uid = N'14AF3C12-38E6-4155-BD29-F33E7966BA23',
@name = @collection_item_name,
@parameters = @parameters,
@frequency = @frequency,
@collection_item_id = @collection_item_id output;
END;
-- for localization of collection item name
UPDATE syscollector_collection_items_internal
SET name_id = @name_id
WHERE collection_item_id = @collection_item_id;
-- Turn the is_system flag on so users can't change the definition of this collection set
UPDATE syscollector_collection_sets
SET is_system = 1
WHERE collection_set_id = @collection_set_id
GO
-- End of installation of out-of-the-box collector components
-- Restore agent xp settings to original state
DECLARE @advopt_old_value int
DECLARE @comp_old_value int
SELECT @advopt_old_value = advopt_old_value FROM #advopt_old_value
SELECT @comp_old_value = comp_old_value FROM #comp_old_value
EXECUTE #sp_restore_component_state 'Agent XPs', @advopt_old_value, @comp_old_value
DROP TABLE #advopt_old_value
DROP TABLE #comp_old_value
---------------------------------------------------------------
-- Data Collector: Security: Permissions
---------------------------------------------------------------
PRINT ''
PRINT 'Granting permissions to data collector roles...'
GRANT SELECT ON [dbo].[syscollector_config_store] TO [dc_operator], [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_enable_collector] TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_disable_collector] TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_set_warehouse_instance_name] TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_set_warehouse_database_name] TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_set_cache_window] TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_set_cache_directory] TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_get_warehouse_connection_string] TO [dc_proxy]
GRANT EXECUTE ON [dbo].[fn_syscollector_highest_incompatible_mdw_version] TO [dc_admin], [dc_proxy]
GRANT SELECT ON [dbo].[syscollector_collector_types] TO [dc_operator], [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_create_collector_type] TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_delete_collector_type] TO [dc_admin]
GRANT SELECT ON [dbo].[syscollector_collection_sets] TO [dc_operator], [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_create_collection_set] TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_delete_collection_set] TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_update_collection_set] TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_start_collection_set] TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_stop_collection_set] TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_upload_collection_set] TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_run_collection_set] TO [dc_operator]
GRANT SELECT ON [dbo].[syscollector_collection_items] TO [dc_operator], [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_create_collection_item] TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_delete_collection_item] TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_update_collection_item] TO [dc_operator]
GRANT SELECT ON [dbo].[syscollector_execution_log] TO [dc_operator]
GRANT SELECT ON [dbo].[syscollector_execution_log_full] TO [dc_operator]
GRANT SELECT ON [dbo].[syscollector_execution_stats] TO [dc_operator]
GRANT EXECUTE ON [dbo].[fn_syscollector_find_collection_set_root] TO [dc_operator]
GRANT SELECT ON [dbo].[fn_syscollector_get_execution_log_tree] TO [dc_operator]
GRANT SELECT ON [dbo].[fn_syscollector_get_execution_stats] TO [dc_operator]
GRANT SELECT ON [dbo].[fn_syscollector_get_execution_details] TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_delete_execution_log_tree] TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_oncollectionbegin] TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_oncollectionend] TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_onpackagebegin] TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_onpackageend] TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_onpackageupdate] TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_onerror] TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_onstatsupdate] TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_create_tsql_query_collector] TO [dc_operator], [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_get_tsql_query_collector_package_ids] TO [dc_operator], [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_verify_subsystems] TO [dc_operator]
---------------------------------------------------------------
-- Relational storage for DMF objects
---------------------------------------------------------------
CREATE TABLE #objects_to_drop(
type nvarchar(128),
name sysname
)
-- List of shared registered server objects to be deleted from msdb. Note: order is important!
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_sysmanagement_verify_shared_server_type]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_sysmanagement_update_shared_registered_server]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_sysmanagement_rename_shared_registered_server]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_sysmanagement_update_shared_server_group]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_sysmanagement_rename_shared_server_group]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_sysmanagement_move_shared_registered_server]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_sysmanagement_delete_shared_registered_server]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_sysmanagement_move_shared_server_group]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_sysmanagement_delete_shared_server_group]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_sysmanagement_add_shared_registered_server]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_sysmanagement_add_shared_server_group]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[sysmanagement_shared_registered_servers]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[sysmanagement_shared_server_groups]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[sysmanagement_delete_shared_server_group_trigger]')
-- List of policy management objects to be deleted from msdb. Note: order is important!
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_insert_target_set_level_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_update_target_set_level_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_insert_target_set_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_delete_target_set_trigger]' )
INSERT INTO #objects_to_drop VALUES ('FUNCTION', '[dbo].[syspolicy_fn_filter_complete]' )
INSERT INTO #objects_to_drop VALUES ('FUNCTION', '[dbo].[syspolicy_fn_eventing_filter]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_add_target_set_condition_reference]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_update_target_set_condition_reference]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_target_set_condition_references]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_add_target_set_level]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_update_target_set_level]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_target_set_levels]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_verify_object_set_identifiers]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_verify_object_set_references]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_add_target_set]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_delete_target_set]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_update_target_set]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_add_object_set]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_delete_object_set]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_target_sets]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_events_reader]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_dispatch_event]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_delete_policy_execution_history]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_log_policy_execution_detail]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_log_policy_execution_end]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_log_policy_execution_start]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_policy_execution_history_details]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_policy_execution_history]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_update_system_health_state]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_system_health_state]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_delete_policy_category_subscription]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_update_policy_category_subscription]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_add_policy_category_subscription]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_policy_category_subscriptions]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_delete_policy]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_update_policy]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_rename_policy]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_verify_policy_identifiers]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_add_policy]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_rename_policy_category]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_update_policy_category]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_delete_policy_category]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_add_policy_category]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_verify_policy_category_identifiers]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_policies]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_create_job]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_delete_job_delete_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_update_policy_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_insert_policy_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_update_job_update_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_insert_job_create_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_instead_delete_policy_trigger]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_policy_categories]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_rename_condition]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_delete_condition]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_update_condition]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_verify_condition_identifiers]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_add_condition]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_conditions]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_insert_condition_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_update_condition_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_for_update_condition_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_after_update_condition_trigger]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_object_sets]' )
INSERT INTO #objects_to_drop VALUES ('FUNCTION', '[dbo].[syspolicy_fn_get_type_name]' )
INSERT INTO #objects_to_drop VALUES ('INLINE FUNCTION', '[dbo].[syspolicy_fn_get_bad_filters]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_check_membership]' )
INSERT INTO #objects_to_drop VALUES ('FUNCTION', '[dbo].[fn_syspolicy_get_ps_command]' )
INSERT INTO #objects_to_drop VALUES ('VIEW', '[dbo].[syspolicy_configuration]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_configure]' )
INSERT INTO #objects_to_drop VALUES ('FUNCTION', '[dbo].[fn_syspolicy_is_automation_enabled]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_set_config_enabled]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_repair_policy_automation]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_purge_history]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_set_config_history_retention]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER', '[dbo].[syspolicy_validate_events]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_create_purge_job]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_purge_health_state]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_set_log_on_success]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', '[dbo].[sp_syspolicy_mark_system]' )
GO
DECLARE @object_name sysname
DECLARE @object_type nvarchar(128)
DECLARE object_to_drop_cursor CURSOR LOCAL FOR SELECT type, name FROM #objects_to_drop
OPEN object_to_drop_cursor
FETCH object_to_drop_cursor INTO @object_type, @object_name
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @stmt nvarchar(128)
DECLARE @object_kind nvarchar(2)
SET @object_kind =
CASE @object_type
WHEN 'VIEW' THEN 'V'
WHEN 'PROCEDURE' THEN 'P'
WHEN 'TRIGGER' THEN 'TR'
WHEN 'FUNCTION' THEN 'FN'
WHEN 'INLINE FUNCTION' THEN 'IF'
WHEN 'TABLE TYPE' THEN 'TT'
ELSE NULL
END
IF @object_kind IS NULL
BEGIN
DECLARE @errtxt nvarchar(max)
SET @errtxt = 'Incorrect object type "' + @object_type + '" for object "' + @object_name + '", check "INSERT INTO #objects_to_drop..." statement'
RAISERROR(@errtxt, 20, 127) WITH LOG
END
IF (OBJECT_ID(@object_name, @object_kind) IS NULL)
PRINT 'Object "' + @object_name + N'" does not exist, will not drop'
ELSE
BEGIN
IF( @object_type = 'INLINE FUNCTION')
SET @object_type = 'FUNCTION'
SET @stmt = N'drop ' + @object_type + N' ' + @object_name
PRINT 'Executing "' + @stmt + N'"'
EXECUTE(@stmt)
END
FETCH object_to_drop_cursor INTO @object_type, @object_name
END
CLOSE object_to_drop_cursor
DEALLOCATE object_to_drop_cursor
DROP TABLE #objects_to_drop
PRINT 'Done dropping all DMF and Shared Registered Server procedures'
GO
--------------------------------------------------------------
-- This section contains shared registered servers information
--------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name ='sysmanagement_shared_server_groups_internal')
BEGIN
PRINT 'Creating table [msdb].[dbo].[sysmanagement_shared_server_groups_internal]...'
CREATE TABLE [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
(
server_group_id INT NOT NULL IDENTITY PRIMARY KEY NONCLUSTERED,
name sysname NOT NULL,
description NVARCHAR (2048) NOT NULL,
-- You can only have a registered server of the same type within a group of the same type
-- So the group needs to have knowledge of its type
server_type INT NOT NULL,
-- Explicitly allow NULLs for this column, so we are independent of server configuration
parent_id INT NULL,
-- this flag indicates whether the group is a system builtin group
is_system_object BIT DEFAULT 0,
-- Make sure each name is unique per parent
CONSTRAINT [UQ_sysmanagement_unique_group_name_per_parent] UNIQUE(parent_id, name)
);
CREATE CLUSTERED INDEX [IX_sysmanagement_shared_server_groups_clustParentGroupID] ON
[dbo].[sysmanagement_shared_server_groups_internal] (parent_id);
CREATE NONCLUSTERED INDEX [IX_sysmanagement_shared_server_groups_name] ON
[dbo].[sysmanagement_shared_server_groups_internal] (name)
-- populate with the builtin server groups
-- Note: server_type_id values must match the ServerType enumeration
INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (name, description, server_type, parent_id, is_system_object)
VALUES (N'DatabaseEngineServerGroup', N'Builtin group that contains the DatabaseEngine servers', 0, null, 1);
INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (name, description, server_type, parent_id, is_system_object)
VALUES (N'AnalysisServicesServerGroup', N'Builtin group that contains the AnalysisServices servers', 1, null, 1);
INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (name, description, server_type, parent_id, is_system_object)
VALUES (N'ReportingServicesServerGroup', N'Builtin group that contains the ReportingServices servers', 2, null, 1);
INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (name, description, server_type, parent_id, is_system_object)
VALUES (N'IntegrationServicesServerGroup', N'Builtin group that contains the IntegrationServices servers', 3, null, 1);
INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (name, description, server_type, parent_id, is_system_object)
VALUES (N'SqlServerCompactEditionServerGroup', N'Builtin group that contains the SqlServerCompactEdition servers', 4, null, 1);
END
ELSE
BEGIN
UPDATE
[msdb].[dbo].[sysmanagement_shared_server_groups_internal]
SET
name = N'SqlServerCompactEditionServerGroup',
description = N'Builtin group that contains the SqlServerCompactEdition servers'
WHERE
name = N'SqlServerEverywhereServerGroup' and
server_type = 4 and
is_system_object = 1;
END
GO
PRINT 'Creating trigger [sysmanagement_delete_shared_server_group_trigger]...'
GO
CREATE TRIGGER [sysmanagement_delete_shared_server_group_trigger] on [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
FOR DELETE
AS
BEGIN
-- system server groups should not be deleted
IF EXISTS (SELECT * FROM deleted where is_system_object = 1)
BEGIN
RAISERROR (35008, 1, 1)
ROLLBACK TRANSACTION
END
END
GO
IF NOT EXISTS ( SELECT * FROM sys.tables WHERE name = 'sysmanagement_shared_registered_servers_internal')
BEGIN
PRINT 'Creating table [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]...'
CREATE TABLE [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
(
server_id INT NOT NULL IDENTITY PRIMARY KEY NONCLUSTERED,
server_group_id INT FOREIGN KEY REFERENCES [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (server_group_id) ON DELETE CASCADE,
name sysname NOT NULL,
server_name sysname NOT NULL,
description NVARCHAR(2048) NOT NULL,
-- While the server group has the knowledge of the server type,
-- you also need the Server Type here, because you can have a root registered server with no parent group
server_type INT NOT NULL,
-- Make sure each registered name is unique in each group
CONSTRAINT [UQ_sysmanagement_unique_server_name_per_group] UNIQUE(server_group_id, name)
)
CREATE CLUSTERED INDEX [IX_sysmanagement_shared_registered_servers_clustGroupID] ON
[dbo].[sysmanagement_shared_registered_servers_internal] (server_group_id);
CREATE NONCLUSTERED INDEX [IX_sysmanagement_shared_registered_servers_name] ON
[dbo].[sysmanagement_shared_registered_servers_internal] (name)
END
GO
PRINT 'Creating view [dbo].[sysmanagement_shared_server_groups]...'
GO
CREATE VIEW [dbo].[sysmanagement_shared_server_groups]
AS
(
SELECT server_group_id, name, description, server_type, parent_id, is_system_object,
(select COUNT(*) from [msdb].[dbo].[sysmanagement_shared_server_groups_internal] sgChild where sgChild.parent_id = sg.server_group_id) as num_server_group_children,
(select COUNT(*) from [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] rsChild where rsChild.server_group_id = sg.server_group_id) as num_registered_server_children
FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] sg
)
GO
PRINT 'Creating view [dbo].[sysmanagement_shared_registered_servers]...'
GO
CREATE VIEW [dbo].[sysmanagement_shared_registered_servers]
AS
(
SELECT server_id, server_group_id, name, server_name, description, server_type
FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
)
GO
PRINT 'Creating procedure [dbo].[sp_sysmanagement_verify_shared_server_type]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_verify_shared_server_type]
@server_type INT
AS
BEGIN
IF (@server_type IS NULL)
BEGIN
RAISERROR (35009, -1, -1)
RETURN(1)
END
-- 0 --> DatabaseEngineServerGroup, 1 --> AnalysisServicesServerGroup, 2 --> ReportingServicesServerGroup, 3 --> IntegrationServicesServerGroup, 4 --> SqlServerCompactEditionServerGroup
IF (@server_type < 0 OR @server_type > 4)
BEGIN
RAISERROR (35010, -1, -1, @server_type)
RETURN (1)
END
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_sysmanagement_add_shared_server_group]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_add_shared_server_group]
@name sysname,
@description NVARCHAR (2048) = N'',
@parent_id INT,
@server_type INT,
@server_group_id INT OUTPUT
AS
BEGIN
DECLARE @retval INT
EXECUTE @retval = sp_sysmanagement_verify_shared_server_type @server_type
IF (@retval <> 0)
RETURN(1) -- Failure
-- user created server groups should have a valid parent
IF( (@parent_id IS NULL) OR
(@parent_id NOT IN (SELECT sg.server_group_id FROM msdb.dbo.sysmanagement_shared_server_groups_internal sg)))
BEGIN
RAISERROR (35001, -1, -1)
RETURN (1)
END
IF EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] sg
WHERE @parent_id = sg.server_group_id AND @server_type <> sg.server_type)
BEGIN
RAISERROR (35002, -1, -1)
RETURN (1)
END
INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
(name, description, parent_id, server_type)
VALUES
(
@name,
@description,
@parent_id,
@server_type
)
SELECT @server_group_id = SCOPE_IDENTITY()
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_sysmanagement_add_shared_registered_server]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_add_shared_registered_server]
@name sysname,
@server_group_id INT,
@server_name sysname,
@description NVARCHAR(2048) = N'',
@server_type INT,
@server_id INT OUTPUT
AS
BEGIN
DECLARE @retval INT
EXECUTE @retval = sp_sysmanagement_verify_shared_server_type @server_type
IF (@retval <> 0)
RETURN(1) -- Failure
IF( (@server_group_id IS NULL) OR
(@server_group_id NOT IN (SELECT sg.server_group_id FROM msdb.dbo.sysmanagement_shared_server_groups_internal sg)))
BEGIN
RAISERROR (35001, -1, -1)
RETURN (1)
END
IF EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] sg
WHERE @server_group_id = sg.server_group_id AND @server_type <> sg.server_type)
BEGIN
RAISERROR (35002, -1, -1)
RETURN (1)
END
IF (@server_name IS NULL)
BEGIN
RAISERROR(14618, -1, 1, '@server_name')
RETURN(1)
END
set @server_name = LTRIM(@server_name)
set @server_name = RTRIM(@server_name)
-- Disallow relative names
IF ('.' = @server_name) OR
(1 = CHARINDEX(N'.\', @server_name)) OR
(1 = CHARINDEX(N'LOCALHOST\', UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS))) OR
(UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = 'LOCALHOST') OR
(UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = '(LOCAL)')
BEGIN
RAISERROR (35011, -1, -1)
RETURN (1)
END
IF (UPPER(@@SERVERNAME collate SQL_Latin1_General_CP1_CS_AS) = UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS))
BEGIN
RAISERROR (35012, -1, -1)
RETURN (1)
END
INSERT INTO [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
(server_group_id, name, server_name, description, server_type)
VALUES
(@server_group_id, @name, @server_name, @description, @server_type)
SELECT @server_id = SCOPE_IDENTITY()
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_sysmanagement_delete_shared_server_group]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_delete_shared_server_group]
@server_group_id INT
AS
BEGIN
IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @server_group_id)
BEGIN
RAISERROR (35004, -1, -1)
RETURN(1)
END;
WITH ChildGroups (parent_id, server_group_id, name, server_type, server_level)
AS
(
-- Anchor
SELECT g.parent_id, g.server_group_id, g.name, g.server_type, 0 AS server_level
FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] AS g
WHERE g.server_group_id = @server_group_id
UNION ALL
-- Recursive definition
SELECT r.parent_id, r.server_group_id, r.name, r.server_type, server_level + 1
FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] AS r
INNER JOIN ChildGroups AS children ON r.parent_id = children.server_group_id
)
-- Execute CTE to delete the hierarchy of server groups
DELETE FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
FROM ChildGroups children
JOIN [msdb].[dbo].[sysmanagement_shared_server_groups_internal] ServerGroups
ON children.server_group_id = ServerGroups.server_group_id
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_sysmanagement_delete_shared_registered_server]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_delete_shared_registered_server]
@server_id INT
AS
BEGIN
IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id)
BEGIN
RAISERROR (35007, -1, -1)
RETURN(1)
END
DELETE FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
WHERE
server_id = @server_id
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_sysmanagement_move_shared_server_group]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_move_shared_server_group]
@server_group_id INT,
@new_parent_id INT
AS
BEGIN
IF (@new_parent_id IS NULL) OR
NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @new_parent_id)
BEGIN
RAISERROR (35001, -1, -1)
RETURN(1)
END
IF (@new_parent_id IS NOT NULL)
AND ((SELECT server_type FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @new_parent_id)
<>
(SELECT server_type FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @server_group_id))
BEGIN
RAISERROR (35002, -1, -1)
RETURN(1)
END
DECLARE @DeletedGroups TABLE
(
server_group_id int
);
-- Check if the destination group you're moving to isn't already a descendant of the current group
WITH ChildGroups (parent_id, server_group_id, server_level)
AS
(
-- Anchor
SELECT g.parent_id, g.server_group_id, 0 AS server_level
FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] AS g
WHERE g.server_group_id = @server_group_id
UNION ALL
-- Recursive definition
SELECT r.parent_id, r.server_group_id, server_level + 1
FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] AS r
INNER JOIN ChildGroups AS children ON r.parent_id = children.server_group_id
)
-- Execute CTE
INSERT INTO @DeletedGroups
SELECT server_group_id FROM ChildGroups
IF (SELECT COUNT(*) FROM @DeletedGroups WHERE server_group_id = @new_parent_id) > 0
BEGIN
RAISERROR (35003, -1, -1)
RETURN(1)
END
UPDATE [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
SET parent_id = @new_parent_id
WHERE
server_group_id = @server_group_id
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_sysmanagement_move_shared_registered_server]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_move_shared_registered_server]
@server_id INT,
@new_parent_id INT
AS
BEGIN
IF (@server_id IS NULL)
BEGIN
RAISERROR (35006, -1, -1)
RETURN(1)
END
IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id)
BEGIN
RAISERROR (35007, -1, -1)
RETURN(1)
END
IF (@new_parent_id IS NULL) OR
NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @new_parent_id)
BEGIN
RAISERROR (35001, -1, -1)
RETURN(1)
END
IF (@new_parent_id IS NOT NULL)
AND ((SELECT server_type FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @new_parent_id)
<>
(SELECT server_type FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id))
BEGIN
RAISERROR (35002, -1, -1)
RETURN(1)
END
UPDATE [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
SET server_group_id = @new_parent_id
WHERE
server_id = @server_id
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_sysmanagement_update_shared_server_group]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_update_shared_server_group]
@server_group_id INT,
@description NVARCHAR (2048) = NULL
AS
BEGIN
IF (@server_group_id IS NULL)
BEGIN
RAISERROR (35005, -1, -1)
RETURN(1)
END
IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @server_group_id)
BEGIN
RAISERROR (35004, -1, -1)
RETURN(1)
END
UPDATE [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
SET description = ISNULL(@description, description)
WHERE
server_group_id = @server_group_id
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_sysmanagement_update_shared_registered_server]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_update_shared_registered_server]
@server_id INT,
@server_name sysname = NULL,
@description NVARCHAR(2048) = NULL
AS
BEGIN
IF (@server_id IS NULL)
BEGIN
RAISERROR (35006, -1, -1)
RETURN(1)
END
IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id)
BEGIN
RAISERROR (35007, -1, -1)
RETURN(1)
END
IF (@server_name IS NULL)
BEGIN
SET @server_name = (select server_name FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id)
END
set @server_name = LTRIM(@server_name)
set @server_name = RTRIM(@server_name)
-- Disallow relative names
IF ('.' = @server_name) OR
(1 = CHARINDEX(N'.\', @server_name)) OR
(1 = CHARINDEX(N'LOCALHOST\', UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS))) OR
(UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = 'LOCALHOST') OR
(UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = '(LOCAL)')
BEGIN
RAISERROR (35011, -1, -1)
RETURN (1)
END
IF (UPPER(@@SERVERNAME collate SQL_Latin1_General_CP1_CS_AS) = UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS))
BEGIN
RAISERROR (35012, -1, -1)
RETURN (1)
END
UPDATE [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
SET server_name = ISNULL(@server_name, server_name),
description = ISNULL(@description, description)
WHERE
server_id = @server_id
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_sysmanagement_rename_shared_server_group]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_rename_shared_server_group]
@server_group_id INT,
@new_name sysname
AS
BEGIN
IF (@server_group_id IS NULL)
BEGIN
RAISERROR (35006, -1, -1)
RETURN(1)
END
IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @server_group_id)
BEGIN
RAISERROR (35007, -1, -1)
RETURN(1)
END
IF (@new_name IS NULL or LEN(@new_name) = 0)
BEGIN
RAISERROR(21263, -1, -1, '@new_name')
RETURN(1) -- Failure
END
UPDATE [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
SET name = @new_name
WHERE
server_group_id = @server_group_id
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_sysmanagement_rename_shared_registered_server]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_rename_shared_registered_server]
@server_id INT,
@new_name sysname
AS
BEGIN
IF (@server_id IS NULL)
BEGIN
RAISERROR (35006, -1, -1)
RETURN(1)
END
IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id)
BEGIN
RAISERROR (35007, -1, -1)
RETURN(1)
END
IF (@new_name IS NULL or LEN(@new_name) = 0)
BEGIN
RAISERROR(21263, -1, -1, '@new_name')
RETURN(1) -- Failure
END
UPDATE [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
SET name = @new_name
WHERE
server_id = @server_id
RETURN (0)
END
GO
-----------------------------------------------------------
-- This section contains facet information
-----------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_management_facets')
BEGIN
PRINT 'Creating table [dbo].[syspolicy_management_facets]...';
CREATE TABLE [dbo].[syspolicy_management_facets] (
management_facet_id int NOT NULL IDENTITY PRIMARY KEY,
name nvarchar(MAX) NOT NULL, -- this is the name of the management facet
execution_mode int NOT NULL
);
END
GO
-- Create a temp table for the facets that are supposed to ship out of the box
-- Later the script will use the temp table to add any new facets to the syspolicy_management_facets table
declare @temp_syspolicy_management_facets TABLE(
name nvarchar(MAX) NOT NULL, -- this is the name of the management facet
execution_mode int NOT NULL);
-- populate the temp table with facets shipping out of the box
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ApplicationRole', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('AsymmetricKey', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Audit', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('AvailabilityDatabase', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('AvailabilityGroup', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('AvailabilityReplica', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('DatabaseReplicaState', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('BackupDevice', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('BrokerPriority', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('BrokerService', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Certificate', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Computer', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Credential', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('CryptographicProvider', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Database', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('DatabaseAuditSpecification', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('DatabaseDdlTrigger', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('DatabaseRole', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('DataFile', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Default', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('DeployedDac', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Endpoint', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Utility', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('FileGroup', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('FullTextCatalog', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('FullTextIndex', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('FullTextStopList', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IAvailabilityGroupState', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IDatabaseMaintenanceFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IDatabaseOptions', 6);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IDatabasePerformanceFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IDatabaseSecurityFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ILoginOptions', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IMultipartNameFacet', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('INameFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ITableOptions', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IUserOptions', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IViewOptions', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Index', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerAuditFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerConfigurationFacet', 6);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerInformation', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerPerformanceFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerProtocolSettingsFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerSecurityFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerSetupFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerSelectionFacet', 0);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerSettings', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ISurfaceAreaConfigurationForAnalysisServer', 0);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ISurfaceAreaConfigurationForReportingServices', 0);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ISurfaceAreaFacet', 6);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('LinkedServer', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('LogFile', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Login', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('MessageType', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('PartitionFunction', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('PartitionScheme', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Processor', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('PlanGuide', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('RemoteServiceBinding', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ResourceGovernor', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ResourcePool', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Rule', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Schema', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('SearchPropertyList', 6);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Server', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ServerAuditSpecification', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ServerDdlTrigger', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ServerRole', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ServiceContract', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ServiceQueue', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ServiceRoute', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Statistic', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('StoredProcedure', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('SymmetricKey', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Synonym', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Sequence', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Table', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Trigger', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('User', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('UserDefinedAggregate', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('UserDefinedDataType', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('UserDefinedFunction', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('UserDefinedTableType', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('UserDefinedType', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('View', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Volume', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('WorkloadGroup', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('XmlSchemaCollection', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IDataFilePerformanceFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ILogFilePerformanceFacet', 4);
-- Facets can be updated and inserted, however deleting a facet is dangerous because of references from conditions
-- Update the modes on the facets
UPDATE facets
SET facets.execution_mode = tempFacets.execution_mode
FROM @temp_syspolicy_management_facets tempFacets, [msdb].[dbo].[syspolicy_management_facets] facets
WHERE tempFacets.name = facets.name AND tempFacets.execution_mode <> facets.execution_mode;
-- Now populate the syspolicy_management_facets table with the facets that are missing in the table
INSERT [msdb].[dbo].[syspolicy_management_facets] (name, execution_mode)
SELECT tempFacets.name, tempFacets.execution_mode
FROM @temp_syspolicy_management_facets tempFacets
WHERE tempFacets.name NOT IN (SELECT distinct facets.name FROM [msdb].[dbo].[syspolicy_management_facets] facets)
GO
---------------------------------------------------------------
-- Relational storage for policy objects
---------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_facet_events')
BEGIN
PRINT 'Creating table [dbo].[syspolicy_facet_events]...';
CREATE TABLE [dbo].[syspolicy_facet_events] (
management_facet_id int NOT NULL REFERENCES [dbo].[syspolicy_management_facets],
event_name sysname NOT NULL, -- this is the name of the event
target_type sysname NOT NULL, -- type of the target (TABLE, PROCEDURE etc.)
target_type_alias sysname NOT NULL); -- this is an alias for the type of the target
-- it can happen that the same target type
-- shows up as different strings in the event
CREATE CLUSTERED INDEX [IX_facet_events_target_type_alias] ON
[dbo].[syspolicy_facet_events] (target_type_alias);
CREATE UNIQUE INDEX [UX_facet_events] ON
[dbo].[syspolicy_facet_events] (management_facet_id, event_name, target_type, target_type_alias);
END
GO
-- The facet events are unique to an installation, thus delete what is there and then insert the new events
-- This technique will work for both a new install and an upgrade.
DELETE FROM [msdb].[dbo].[syspolicy_facet_events]
-- this is a pseudo event, so we're inserting it before the
-- consistency check is in place
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'SAC_ENDPOINT_CHANGE',N'SERVER',N'SERVER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ISurfaceAreaFacet'
GO
CREATE TRIGGER [syspolicy_validate_events] on [dbo].[syspolicy_facet_events]
AFTER INSERT, UPDATE
AS
BEGIN
-- make sure that caller is dbo and all events inserted are real events.
IF (USER_ID() != 1) OR
EXISTS (SELECT event_name FROM inserted
WHERE event_name NOT IN(SELECT type_name from sys.event_notification_event_types))
BEGIN
RAISERROR(N'Unknown event name inserted into [dbo].[syspolicy_facet_events]', 1,1)
ROLLBACK TRANSACTION
END
END
GO
-- Insert the facet events
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_APPLICATION_ROLE',N'APPLICATION ROLE',N'APPLICATION ROLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ApplicationRole'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_APPLICATION_ROLE',N'APPLICATION ROLE',N'APPLICATION ROLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ApplicationRole'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_ASYMMETRIC_KEY',N'ASYMMETRICKEY',N'ASYMMETRIC KEY'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'AsymmetricKey'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_ASYMMETRIC_KEY',N'ASYMMETRICKEY',N'ASYMMETRIC KEY'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'AsymmetricKey'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'ASYMMETRICKEY',N'ASYMMETRIC KEY'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'AsymmetricKey'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_ROLE',N'ROLE',N'ROLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'DatabaseRole'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_ROLE',N'ROLE',N'ROLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'DatabaseRole'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'ROLE',N'ROLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'DatabaseRole'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_ENDPOINT',N'ENDPOINT',N'ENDPOINT'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'Endpoint'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_ENDPOINT',N'ENDPOINT',N'ENDPOINT'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'Endpoint'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_SERVER',N'ENDPOINT',N'ENDPOINT'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'Endpoint'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_DATABASE',N'DATABASE',N'DATABASE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IDatabaseOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_DATABASE',N'DATABASE',N'DATABASE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IDatabaseOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'DATABASE',N'DATABASE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IDatabaseOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_FUNCTION',N'FUNCTION',N'FUNCTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_FUNCTION',N'FUNCTION',N'FUNCTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'RENAME',N'FUNCTION',N'FUNCTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_PROCEDURE',N'PROCEDURE',N'PROCEDURE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_PROCEDURE',N'PROCEDURE',N'PROCEDURE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'RENAME',N'PROCEDURE',N'PROCEDURE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_SYNONYM',N'SYNONYM',N'SYNONYM'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_TABLE',N'TABLE',N'TABLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_TABLE',N'TABLE',N'TABLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'RENAME',N'TABLE',N'TABLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_TYPE',N'TYPE',N'TYPE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'RENAME',N'TYPE',N'TYPE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_VIEW',N'VIEW',N'VIEW'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_VIEW',N'VIEW',N'VIEW'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'RENAME',N'VIEW',N'VIEW'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_XML_SCHEMA_COLLECTION',N'XMLSCHEMACOLLECTION',N'XMLSCHEMACOLLECTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_XML_SCHEMA_COLLECTION',N'XMLSCHEMACOLLECTION',N'XMLSCHEMACOLLECTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'RENAME',N'XMLSCHEMACOLLECTION',N'XMLSCHEMACOLLECTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'TABLE',N'TABLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'VIEW',N'VIEW'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'FUNCTION',N'FUNCTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'PROCEDURE',N'PROCEDURE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'SYNONYM',N'SYNONYM'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'TYPE',N'TYPE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'XMLSCHEMACOLLECTION',N'XMLSCHEMACOLLECTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'AUDIT_SERVER_OPERATION_EVENT',N'SERVER',N'SERVER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IServerConfigurationFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'AUDIT_SERVER_OPERATION_EVENT',N'SERVER',N'SERVER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ISurfaceAreaFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_ENDPOINT',N'SERVER',N'SERVER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ISurfaceAreaFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_ENDPOINT',N'SERVER',N'SERVER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ISurfaceAreaFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'DROP_ENDPOINT',N'SERVER',N'SERVER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ISurfaceAreaFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_LOGIN',N'LOGIN',N'LOGIN'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ILoginOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_LOGIN',N'LOGIN',N'LOGIN'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ILoginOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_RESOURCE_POOL',N'RESOURCEPOOL',N'RESOURCE POOL'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ResourcePool'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_RESOURCE_POOL',N'RESOURCEPOOL',N'RESOURCE POOL'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ResourcePool'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'SCHEMA',N'SCHEMA'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'Schema'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_SCHEMA',N'SCHEMA',N'SCHEMA'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'Schema'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'SCHEMA',N'SCHEMA'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'Schema'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SERVER_ROLE',N'SERVER ROLE',N'SERVER ROLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ServerRole'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_SERVER_ROLE',N'SERVER ROLE',N'SERVER ROLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ServerRole'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_SERVER',N'SERVER ROLE',N'SERVER ROLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ServerRole'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SEQUENCE',N'SEQUENCE',N'SEQUENCE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'Sequence'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_SEQUENCE',N'SEQUENCE',N'SEQUENCE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'Sequence'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'RENAME',N'SEQUENCE',N'SEQUENCE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'Sequence'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'SEQUENCE',N'SEQUENCE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'Sequence'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'SEQUENCE',N'SEQUENCE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'Sequence'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_PROCEDURE',N'PROCEDURE',N'PROCEDURE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'StoredProcedure'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_PROCEDURE',N'PROCEDURE',N'PROCEDURE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'StoredProcedure'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'RENAME',N'PROCEDURE',N'PROCEDURE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'StoredProcedure'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'PROCEDURE',N'PROCEDURE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'StoredProcedure'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'PROCEDURE',N'PROCEDURE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'StoredProcedure'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_TABLE',N'TABLE',N'TABLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ITableOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_TABLE',N'TABLE',N'TABLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ITableOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'RENAME',N'TABLE',N'TABLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ITableOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'TABLE',N'TABLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ITableOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'TABLE',N'TABLE'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'ITableOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_USER',N'USER',N'ASYMMETRIC KEY USER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_USER',N'USER',N'CERTIFICATE USER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_USER',N'USER',N'GROUP USER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_USER',N'USER',N'SQL USER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_USER',N'USER',N'WINDOWS USER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_USER',N'USER',N'ASYMMETRIC KEY USER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_USER',N'USER',N'CERTIFICATE USER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_USER',N'USER',N'GROUP USER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_USER',N'USER',N'SQL USER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_USER',N'USER',N'WINDOWS USER'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_FUNCTION',N'FUNCTION',N'FUNCTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'UserDefinedFunction'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_FUNCTION',N'FUNCTION',N'FUNCTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'UserDefinedFunction'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'RENAME',N'FUNCTION',N'FUNCTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'UserDefinedFunction'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'FUNCTION',N'FUNCTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'UserDefinedFunction'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'FUNCTION',N'FUNCTION'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'UserDefinedFunction'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_VIEW',N'VIEW',N'VIEW'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IViewOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_VIEW',N'VIEW',N'VIEW'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IViewOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'RENAME',N'VIEW',N'VIEW'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IViewOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'VIEW',N'VIEW'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IViewOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SCHEMA',N'VIEW',N'VIEW'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'IViewOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_WORKLOAD_GROUP',N'WORKLOADGROUP',N'WORKLOAD GROUP'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'WorkloadGroup'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_WORKLOAD_GROUP',N'WORKLOADGROUP',N'WORKLOAD GROUP'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'WorkloadGroup'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_SEARCH_PROPERTY_LIST',N'SEARCHPROPERTYLIST',N'SEARCH PROPERTY LIST'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'SearchPropertyList'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'CREATE_SEARCH_PROPERTY_LIST',N'SEARCHPROPERTYLIST',N'SEARCH PROPERTY LIST'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'SearchPropertyList'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias)
SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'SEARCHPROPERTYLIST',N'SEARCH PROPERTY LIST'
FROM [msdb].[dbo].[syspolicy_management_facets]
WHERE name = 'SearchPropertyList'
GO
---------------------------------------------------------------
-- Condition object
---------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_conditions_internal')
BEGIN
PRINT 'Creating table [dbo].[syspolicy_conditions_internal]...'
CREATE TABLE [dbo].[syspolicy_conditions_internal] (
condition_id int IDENTITY(1,1),
name sysname NOT NULL,
date_created datetime default GETDATE(),
description nvarchar(max) NOT NULL default (''),
created_by sysname NOT NULL default SUSER_SNAME(),
modified_by sysname NULL,
date_modified datetime NULL,
facet_id int,
expression nvarchar(max),
is_name_condition smallint default (0),
obj_name sysname NULL,
is_system bit NOT NULL default (0),
CONSTRAINT [PK_syspolicy_conditions] PRIMARY KEY CLUSTERED (condition_id ASC),
CONSTRAINT [UQ_syspolicy_conditions_name] UNIQUE(name)
);
ALTER TABLE [dbo].[syspolicy_conditions_internal]
ADD CONSTRAINT [FK_syspolicy_conditions_internal_facet] FOREIGN KEY(facet_id)
REFERENCES [dbo].[syspolicy_management_facets] (management_facet_id);
END
GO
PRINT 'Creating view [dbo].[syspolicy_conditions]...'
GO
CREATE VIEW [dbo].[syspolicy_conditions]
AS
SELECT
c.condition_id, c.name, c.date_created, c.description, c.created_by,
c.modified_by, c.date_modified, c.is_name_condition, mf.name AS facet, c.expression, c.obj_name, c.is_system
FROM [dbo].[syspolicy_conditions_internal] c
LEFT OUTER JOIN [dbo].[syspolicy_management_facets] mf ON c.facet_id = mf.management_facet_id
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_check_membership]
@role sysname,
@raiserror bit = 1
AS
BEGIN
-- make sure that the caller is dbo or @role
IF ( IS_MEMBER(@role) != 1 AND USER_ID() != 1)
BEGIN
IF (@raiserror = 1)
BEGIN
RAISERROR(15003, -1, -1, @role);
END
RETURN 15003;
END
RETURN 0;
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_add_condition]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_condition]
@name sysname,
@description nvarchar(max) = N'',
@facet nvarchar(max),
@expression nvarchar(max),
@is_name_condition smallint = 0,
@obj_name sysname = NULL,
@condition_id int = NULL OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
DECLARE @facet_id INT
DECLARE @null_column sysname
SET @null_column = NULL
IF (@name IS NULL OR @name = N'')
SET @null_column = '@name'
ELSE IF( @description IS NULL)
SET @null_column = '@description'
ELSE IF( @facet IS NULL)
SET @null_column = '@facet'
ELSE IF( @expression IS NULL)
SET @null_column = '@expression'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_syspolicy_add_condition')
RETURN(1)
END
IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_conditions WHERE name = @name)
BEGIN
RAISERROR(34010, -1, -1, 'Condition', @name)
RETURN(1)
END
SET @facet_id = (SELECT management_facet_id FROM [dbo].[syspolicy_management_facets] WHERE name = @facet)
IF (@facet_id IS NULL)
BEGIN
RAISERROR (34014, -1, -1)
RETURN(1)
END
INSERT INTO msdb.dbo.syspolicy_conditions_internal(name, description,facet_id,expression,is_name_condition,obj_name)
VALUES(@name, @description,@facet_id,@expression,@is_name_condition,@obj_name)
SELECT @retval = @@error
SET @condition_id = SCOPE_IDENTITY()
RETURN(@retval)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_verify_condition_identifiers]...'
GO
-----------------------------------------------------------
-- This procedure verifies if a condition exists
-- The caller can pass either the condition name or the id
-----------------------------------------------------------
CREATE PROCEDURE [dbo].[sp_syspolicy_verify_condition_identifiers]
@condition_name sysname = NULL OUTPUT,
@condition_id int = NULL OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
IF ((@condition_name IS NULL) AND (@condition_id IS NULL)) OR
((@condition_name IS NOT NULL) AND (@condition_id IS NOT NULL))
BEGIN
RAISERROR(14524, -1, -1, '@condition_name', '@condition_id')
RETURN(1) -- Failure
END
-- Check id
IF (@condition_id IS NOT NULL)
BEGIN
SELECT @condition_name = name
FROM msdb.dbo.syspolicy_conditions
WHERE (condition_id = @condition_id)
-- the view would take care of all the permissions issues.
IF (@condition_name IS NULL)
BEGIN
DECLARE @condition_id_as_char VARCHAR(36)
SELECT @condition_id_as_char = CONVERT(VARCHAR(36), @condition_id)
RAISERROR(14262, -1, -1, '@condition_id', @condition_id_as_char)
RETURN(1) -- Failure
END
END
ELSE
-- Check name
IF (@condition_name IS NOT NULL)
BEGIN
-- get the corresponding condition_id (if the condition exists)
SELECT @condition_id = condition_id
FROM msdb.dbo.syspolicy_conditions
WHERE (name = @condition_name)
-- the view would take care of all the permissions issues.
IF (@condition_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@condition_name', @condition_name)
RETURN(1) -- Failure
END
END
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_update_condition]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_condition]
@name sysname = NULL,
@condition_id int = NULL,
@facet nvarchar(max) = NULL,
@expression nvarchar(max) = NULL,
@description nvarchar(max) = NULL,
@is_name_condition smallint = NULL,
@obj_name sysname = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
DECLARE @facet_id INT
EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @name, @condition_id OUTPUT
IF (@retval <> 0)
RETURN (1)
IF (@facet IS NOT NULL)
BEGIN
SET @facet_id = (SELECT management_facet_id FROM [dbo].[syspolicy_management_facets] WHERE name = @facet)
IF (@facet_id IS NULL)
BEGIN
RAISERROR (34014, -1, -1)
RETURN(1)
END
END
UPDATE msdb.[dbo].[syspolicy_conditions_internal]
SET
description = ISNULL(@description, description),
facet_id = ISNULL(@facet_id, facet_id),
expression = ISNULL(@expression, expression),
is_name_condition = ISNULL(@is_name_condition, is_name_condition),
obj_name = ISNULL(@obj_name, obj_name)
WHERE condition_id = @condition_id
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_condition]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_condition]
@name sysname = NULL,
@condition_id int = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
EXEC @retval = sp_syspolicy_verify_condition_identifiers @name, @condition_id OUTPUT
IF (@retval <> 0)
RETURN (1)
IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_policies WHERE condition_id = @condition_id)
BEGIN
RAISERROR(34012,-1,-1,'Condition','Policy')
RETURN (1)
END
DELETE msdb.dbo.syspolicy_conditions_internal
WHERE condition_id = @condition_id
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_rename_condition]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_rename_condition]
@name sysname = NULL,
@condition_id int = NULL,
@new_name sysname = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
IF (@new_name IS NULL or LEN(@new_name) = 0)
BEGIN
RAISERROR(21263, -1, -1, '@new_name')
RETURN(1) -- Failure
END
DECLARE @retval INT
EXEC @retval = sp_syspolicy_verify_condition_identifiers @name, @condition_id OUTPUT
IF (@retval <> 0)
RETURN (1)
UPDATE msdb.[dbo].[syspolicy_conditions_internal]
SET name = @new_name
WHERE condition_id = @condition_id
SELECT @retval = @@error
RETURN(@retval)
END
GO
---------------------------------------------------------------
-- table for Policy category
---------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_policy_categories_internal')
BEGIN
PRINT 'Creating table [dbo].[syspolicy_policy_categories_internal]...';
CREATE TABLE [dbo].[syspolicy_policy_categories_internal] (
policy_category_id int IDENTITY(1,1),
name sysname,
mandate_database_subscriptions bit default 1 NOT NULL,
CONSTRAINT [PK_syspolicy_policy_categories] PRIMARY KEY CLUSTERED (policy_category_id ASC),
CONSTRAINT [UQ_syspolicy_policy_categories_name] UNIQUE(name)
);
END
GO
PRINT 'Creating view [dbo].[syspolicy_policy_categories]...'
GO
CREATE VIEW [dbo].[syspolicy_policy_categories]
AS
SELECT
policy_category_id,
name,
mandate_database_subscriptions
FROM [dbo].[syspolicy_policy_categories_internal]
GO
---------------------------------------------------------------
-- ObjectSet object
---------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_object_sets_internal')
BEGIN
PRINT 'Creating table [dbo].[syspolicy_object_sets_internal]...'
CREATE TABLE [dbo].[syspolicy_object_sets_internal] (
object_set_id int NOT NULL IDENTITY(1,1),
object_set_name sysname NOT NULL,
facet_id int,
is_system bit NOT NULL default (0),
CONSTRAINT [PK_syspolicy_object_sets] PRIMARY KEY CLUSTERED (object_set_id),
CONSTRAINT [UQ_syspolicy_object_sets_name] UNIQUE(object_set_name)
)
ALTER TABLE [dbo].[syspolicy_object_sets_internal]
ADD CONSTRAINT [FK_syspolicy_object_sets_syspolicy_management_facets] FOREIGN KEY(facet_id)
REFERENCES [dbo].[syspolicy_management_facets] (management_facet_id)
ON DELETE CASCADE
END
GO
PRINT 'Creating view [dbo].[syspolicy_object_sets]...'
GO
CREATE VIEW [dbo].[syspolicy_object_sets]
AS
SELECT
os.object_set_id,
os.object_set_name,
os.facet_id,
facet.name as facet_name,
os.is_system
FROM [dbo].[syspolicy_object_sets_internal] AS os INNER JOIN [dbo].[syspolicy_management_facets] AS facet
ON os.facet_id = facet.management_facet_id
GO
-----------------------------------------------------------
-- This procedure verifies if a object set definition exists
-- The caller can pass either the name or the id
-----------------------------------------------------------
PRINT 'Creating procedure [dbo].[sp_syspolicy_verify_object_set_identifiers]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_verify_object_set_identifiers]
@name sysname = NULL OUTPUT,
@object_set_id int = NULL OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
IF ((@name IS NULL) AND (@object_set_id IS NULL)) OR
((@name IS NOT NULL) AND (@object_set_id IS NOT NULL))
BEGIN
-- TODO: Verify the error message is appropriate for object sets as well and not specific to policies
RAISERROR(14524, -1, -1, '@name', '@object_set_id')
RETURN(1) -- Failure
END
-- Check id
IF (@object_set_id IS NOT NULL)
BEGIN
SELECT @name = object_set_name
FROM msdb.dbo.syspolicy_object_sets
WHERE (object_set_id = @object_set_id)
-- the view would take care of all the permissions issues.
IF (@name IS NULL)
BEGIN
-- TODO: Where did 36 come from? Is this the total lenght of characters for an int?
DECLARE @object_set_id_as_char VARCHAR(36)
SELECT @object_set_id_as_char = CONVERT(VARCHAR(36), @object_set_id)
RAISERROR(14262, -1, -1, '@object_set_id', @object_set_id_as_char)
RETURN(1) -- Failure
END
END
ELSE
-- Check name
IF (@name IS NOT NULL)
BEGIN
-- get the corresponding object_set_id (if the object_set exists)
SELECT @object_set_id = object_set_id
FROM msdb.dbo.syspolicy_object_sets
WHERE (object_set_name = @name)
-- the view would take care of all the permissions issues.
IF (@object_set_id IS NULL)
BEGIN
-- TODO: Verify the error message is appropriate for object sets as well and not specific to policies
RAISERROR(14262, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
END
RETURN (0)
END
GO
-----------------------------------------------------------
-- This procedure verifies if an object set is refernced (cannot be deleted)
-----------------------------------------------------------
PRINT 'Creating procedure [dbo].[sp_syspolicy_verify_object_set_references]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_verify_object_set_references]
@object_set_id int,
@is_referenced int OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
SELECT @is_referenced = count(*) FROM dbo.syspolicy_policies WHERE object_set_id = @object_set_id
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_add_object_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_object_set]
@object_set_name sysname,
@facet nvarchar (max),
@object_set_id int OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
DECLARE @facet_id INT
DECLARE @null_column sysname
IF( @facet IS NULL)
SET @null_column = '@facet'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_syspolicy_add_object_set')
RETURN(1)
END
SET @facet_id = (SELECT management_facet_id FROM [dbo].[syspolicy_management_facets] WHERE name = @facet)
IF (@facet_id IS NULL)
BEGIN
RAISERROR (34014, -1, -1)
RETURN(1)
END
INSERT INTO msdb.[dbo].[syspolicy_object_sets_internal]
(object_set_name,
facet_id)
VALUES
(@object_set_name,
@facet_id)
SELECT @retval = @@error
SET @object_set_id = SCOPE_IDENTITY()
RETURN(@retval)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_object_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_object_set]
@object_set_name sysname = NULL,
@object_set_id int = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
EXEC @retval = sp_syspolicy_verify_object_set_identifiers @object_set_name, @object_set_id OUTPUT
IF (@retval <> 0)
RETURN (1)
DELETE msdb.[dbo].[syspolicy_object_sets_internal]
WHERE object_set_id = @object_set_id
RETURN (0)
END
GO
---------------------------------------------------------------
-- PolicyDefinition object
---------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_policies_internal')
BEGIN
PRINT 'Creating table [dbo].[syspolicy_policies_internal]...';
CREATE TABLE [dbo].[syspolicy_policies_internal] (
policy_id int IDENTITY(1,1),
name sysname NOT NULL,
condition_id int NOT NULL,
root_condition_id int NULL,
date_created datetime NOT NULL default GETDATE(),
execution_mode int NOT NULL default (0),
policy_category_id int NULL,
schedule_uid uniqueidentifier NULL,
description nvarchar(max) NOT NULL default (''),
help_text nvarchar(4000) NOT NULL default (''),
help_link nvarchar(2083) NOT NULL default (''),
object_set_id INT NULL,
is_enabled bit default 0 NOT NULL,
job_id uniqueidentifier NULL,
created_by sysname NOT NULL default SUSER_SNAME(),
modified_by sysname NULL,
date_modified datetime NULL,
is_system bit NOT NULL default (0),
CONSTRAINT [PK_syspolicy_policies] PRIMARY KEY CLUSTERED (policy_id ASC),
CONSTRAINT [UQ_syspolicy_policies_name] UNIQUE(name)
);
ALTER TABLE [dbo].[syspolicy_policies_internal]
ADD CONSTRAINT [FK_syspolicy_policies_syspolicy_conditions] FOREIGN KEY(condition_id)
REFERENCES [dbo].[syspolicy_conditions_internal] (condition_id);
ALTER TABLE [dbo].[syspolicy_policies_internal]
ADD CONSTRAINT [FK_syspolicy_policies_syspolicy_policy_categories] FOREIGN KEY(policy_category_id)
REFERENCES [dbo].[syspolicy_policy_categories_internal] (policy_category_id);
ALTER TABLE [dbo].[syspolicy_policies_internal]
ADD CONSTRAINT [FK_syspolicy_policies_syspolicy_root_conditions] FOREIGN KEY(root_condition_id)
REFERENCES [dbo].[syspolicy_conditions_internal] (condition_id);
ALTER TABLE [dbo].[syspolicy_policies_internal]
ADD CONSTRAINT [FK_syspolicy_policies_sysjobs] FOREIGN KEY(job_id)
REFERENCES [dbo].[sysjobs] (job_id);
ALTER TABLE [dbo].[syspolicy_policies_internal]
ADD CONSTRAINT [FK_syspolicy_policies_syspolicy_object_sets] FOREIGN KEY(object_set_id)
REFERENCES [dbo].[syspolicy_object_sets_internal] (object_set_id);
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_create_job]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_create_job]
@schedule_uid uniqueidentifier,
@is_enabled bit = 0,
@jobID uniqueidentifier OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @job_name sysname
-- create unique job name
SET @job_name = N'syspolicy_check_schedule_' + LEFT(CONVERT(nvarchar(100), @schedule_uid), 100)
WHILE (EXISTS (SELECT * FROM msdb..sysjobs WHERE name = @job_name))
BEGIN
SET @job_name = N'syspolicy_check_schedule_' + LEFT(CONVERT(nvarchar(91), @schedule_uid), 91) + '_' + RIGHT(STR(FLOOR(RAND() * 100000000)),8)
END
EXEC msdb.dbo.sp_add_job @job_name=@job_name,
@enabled=@is_enabled,
@notify_level_eventlog=0,
@notify_level_email=2,
@notify_level_netsend=2,
@notify_level_page=2,
@delete_level=0,
@category_id=0, -- [Uncategorized (Local)]
@job_id = @jobID OUTPUT
EXEC msdb.dbo.sp_add_jobserver @job_name=@job_name, @server_name = @@servername
EXEC msdb.dbo.sp_add_jobstep
@job_id=@jobID,
@step_name=N'Verify that automation is enabled.',
@step_id=1,
@cmdexec_success_code=0,
@on_fail_action=1,
@on_fail_step_id=0,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'TSQL',
@command=N'IF (msdb.dbo.fn_syspolicy_is_automation_enabled() != 1)
BEGIN
RAISERROR(34022, 16, 1)
END',
@database_name=N'master',
@flags=0
DECLARE @command nvarchar(max)
SET @command = [dbo].[fn_syspolicy_get_ps_command] (@schedule_uid)
EXEC msdb.dbo.sp_add_jobstep
@job_id=@jobID,
@step_name=N'Evaluate policies.',
@step_id=2,
@cmdexec_success_code=0,
@on_success_action=1,
@on_fail_action=2,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'PowerShell',
@command=@command,
@flags=0
EXEC msdb.dbo.sp_update_jobstep
@job_id = @jobID,
@step_id = 1,
@on_success_action=4,
@on_success_step_id=2
DECLARE @schedule_id int
SELECT @schedule_id = schedule_id from msdb.dbo.sysschedules where schedule_uid = @schedule_uid
EXEC msdb.dbo.sp_attach_schedule @job_name = @job_name, @schedule_id = @schedule_id
END
GO
PRINT 'Creating function [dbo].[fn_syspolicy_get_ps_command] ...'
GO
CREATE FUNCTION [dbo].[fn_syspolicy_get_ps_command] (@schedule_uid uniqueidentifier)
RETURNS nvarchar(max)
AS
BEGIN
DECLARE @schedule_uid_string nvarchar(max);
SET @schedule_uid_string = CONVERT(nvarchar(36), @schedule_uid);
-- translate to PSPath root name, for default instances
-- we need to add \default as instance name
DECLARE @root_name nvarchar(100);
SET @root_name = @@SERVERNAME
IF( 0 = CHARINDEX('\', @@SERVERNAME))
SET @root_name = @root_name + N'\default';
DECLARE @command nvarchar(max);
SET @command = N'dir SQLSERVER:\SQLPolicy\' + @root_name +
N'\Policies | where { $_.ScheduleUid -eq "' + @schedule_uid_string +
N'" } | where { $_.Enabled -eq 1} | where {$_.AutomatedPolicyEvaluationMode -eq 4} | Invoke-PolicyEvaluation -AdHocPolicyEvaluationMode 2 -TargetServerName ' + @@SERVERNAME
RETURN @command
END
GO
PRINT 'Creating trigger [dbo].[syspolicy_insert_job_create_trigger] on [dbo].[syspolicy_policies_internal]'
GO
CREATE TRIGGER [dbo].[syspolicy_insert_job_create_trigger] on [dbo].[syspolicy_policies_internal]
FOR INSERT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
-- protect against non-scheduled automation jobs
-- that have expressions that execute script
DECLARE @row_count int
SELECT @row_count = count(*)
FROM syspolicy_conditions c
INNER JOIN inserted i ON (i.condition_id = c.condition_id OR i.root_condition_id = c.condition_id)
WHERE i.is_enabled != 0 AND
i.execution_mode != 4 AND
(1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) )
OPTION (FORCE ORDER);
SELECT @row_count = @row_count + count(*)
FROM dbo.syspolicy_target_set_levels l
INNER JOIN dbo.syspolicy_target_sets s ON s.target_set_id = l.target_set_id
INNER JOIN syspolicy_conditions c on c.condition_id = l.condition_id
INNER JOIN syspolicy_object_sets_internal os ON os.object_set_id = s.object_set_id
INNER JOIN inserted i ON os.object_set_id = i.object_set_id
WHERE i.is_enabled != 0 AND
i.execution_mode != 4 AND
(1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) )
OPTION (FORCE ORDER);
IF (@row_count > 0)
BEGIN
RAISERROR(34017, -1, -1);
ROLLBACK TRANSACTION;
END
DECLARE @jobID uniqueidentifier
DECLARE @schedule_uid uniqueidentifier
DECLARE @is_enabled bit
-- verify that values in inserted.schedule_uid are valid
IF EXISTS (
SELECT * FROM inserted i
WHERE i.schedule_uid NOT IN
(SELECT schedule_uid FROM msdb.dbo.sysschedules ) AND
((i.execution_mode & 4) = 4))
BEGIN
ROLLBACK -- Failure
RAISERROR (14365, -1, -1)
RETURN
END
-- find all schedules referenced by the inserted policies for which
-- there is no agent job that executes the policies
DECLARE schedule_cursor CURSOR LOCAL FOR
SELECT DISTINCT i.schedule_uid
FROM inserted i
WHERE
((i.execution_mode & 4) = 4) AND
NOT EXISTS (SELECT *
FROM msdb.dbo.syspolicy_policies p
WHERE
p.policy_id NOT IN (SELECT policy_id FROM inserted) AND
p.schedule_uid = i.schedule_uid AND
((p.execution_mode & 4) = 4) )
-- iterate through the cursor and create a job for every schedule
OPEN schedule_cursor
FETCH schedule_cursor INTO @schedule_uid
WHILE @@FETCH_STATUS = 0
BEGIN
-- figure out if the job is enabled or not
SELECT @is_enabled = COUNT(*)
FROM inserted i
WHERE i.schedule_uid = @schedule_uid AND i.is_enabled = 1
-- explicitly nullify jobID,
-- (if we need to create more than 1 job, it will not be null and sp_add_job will think we're getting job from MSX)
SET @jobID = NULL
-- create the job that is going to execute the schedule
EXEC [msdb].[dbo].[sp_syspolicy_create_job] @schedule_uid, @is_enabled, @jobID OUTPUT
-- update the job_id back into the policies table
UPDATE p SET p.job_id = @jobID
FROM msdb.dbo.syspolicy_policies_internal p
INNER JOIN inserted i ON p.policy_id = i.policy_id
WHERE
i.schedule_uid = @schedule_uid AND
(i.execution_mode & 4) = 4
FETCH schedule_cursor INTO @schedule_uid
END
CLOSE schedule_cursor
DEALLOCATE schedule_cursor
-- in case we haven't created the job we still need to update
-- the policies with their jobID
UPDATE p
SET p.job_id = ( SELECT TOP 1 p2.job_id
FROM msdb.dbo.syspolicy_policies p2
WHERE
p2.schedule_uid = p.schedule_uid AND
p2.job_id IS NOT NULL)
FROM msdb.dbo.syspolicy_policies_internal p
INNER JOIN inserted i ON p.policy_id = i.policy_id
WHERE
((p.execution_mode & 4) = 4) AND
p.job_id IS NULL
-- See what jobs we need to enable.
-- This can happen because we might create a new policy that
-- is enabled and there is already a job for it, but the existing
-- job is disabled
DECLARE jobs_to_enable CURSOR LOCAL FOR
SELECT DISTINCT j.job_id
FROM dbo.sysjobs_view j
JOIN msdb.dbo.syspolicy_policies p ON p.job_id = j.job_id
JOIN inserted i ON p.policy_id = i.policy_id
WHERE
((i.execution_mode & 4) = 4) AND
j.enabled = 0 AND
EXISTS ( SELECT * from msdb.dbo.syspolicy_policies p2
WHERE p2.job_id = j.job_id AND p2.is_enabled = 1)
OPEN jobs_to_enable
FETCH jobs_to_enable INTO @jobID
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC msdb.dbo.sp_update_job @job_id = @jobID, @enabled = 1
FETCH jobs_to_enable INTO @jobID
END
CLOSE jobs_to_enable
DEALLOCATE jobs_to_enable
-- enable events infrastructure
IF EXISTS ( SELECT * FROM inserted i WHERE ((i.execution_mode & 1) = 1))
BEGIN
EXEC sys.sp_syspolicy_update_ddl_trigger
END
IF EXISTS (SELECT * FROM inserted i WHERE ((i.execution_mode & 2) = 2))
BEGIN
EXEC sys.sp_syspolicy_update_event_notification
END
-- update owner information
UPDATE msdb.dbo.syspolicy_policies_internal
SET created_by = original_login(),
date_created = getdate (),
date_modified = NULL,
modified_by = NULL
FROM inserted i,
msdb.dbo.syspolicy_policies_internal policies
WHERE i.policy_id = policies.policy_id
END -- create trigger
GO
PRINT 'Creating trigger [dbo].[syspolicy_update_job_update_trigger] on [dbo].[syspolicy_policies_internal]'
GO
CREATE TRIGGER [dbo].[syspolicy_update_job_update_trigger] on [dbo].[syspolicy_policies_internal]
FOR UPDATE
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
-- This is to prevent indirect entrance of the trigger
IF (TRIGGER_NESTLEVEL() > 1) RETURN
-- verify that values in inserted.schedule_uid are valid
IF EXISTS (
SELECT * FROM inserted i
WHERE i.schedule_uid NOT IN
(SELECT schedule_uid FROM msdb.dbo.sysschedules ) AND
((i.execution_mode & 4) = 4))
BEGIN
ROLLBACK -- Failure
RAISERROR (14365, -1, -1)
RETURN
END
-- update eventing infrastructure
IF(UPDATE(execution_mode) OR UPDATE(is_enabled))
BEGIN
IF EXISTS (SELECT *
FROM inserted i
INNER JOIN deleted d ON i.policy_id = d.policy_id
WHERE
(((i.execution_mode & 1) = 1) OR ((d.execution_mode & 1) = 1)) AND
(i.is_enabled != d.is_enabled OR i.execution_mode != d.execution_mode))
BEGIN
EXEC sys.sp_syspolicy_update_ddl_trigger
END
IF EXISTS (SELECT *
FROM inserted i
INNER JOIN deleted d ON i.policy_id = d.policy_id
WHERE
(((i.execution_mode & 2) = 2) OR ((d.execution_mode & 2) = 2)) AND
(i.is_enabled != d.is_enabled OR i.execution_mode != d.execution_mode))
BEGIN
EXEC sys.sp_syspolicy_update_event_notification
END
END
DECLARE @jobID uniqueidentifier
DECLARE @is_enabled bit
DECLARE @schedule_uid uniqueidentifier
-- set the job_id to NULL for all policies whose schedule_uid has changed
-- so that we can create a job if needed
UPDATE p
SET p.job_id = NULL
FROM msdb.dbo.syspolicy_policies p
INNER JOIN inserted i ON p.policy_id = i.policy_id
INNER JOIN deleted d ON d.policy_id = p.policy_id
WHERE i.schedule_uid != d.schedule_uid
-- find all schedules referenced by the inserted policies for which
-- there is no agent job that executes the policies
DECLARE schedule_cursor CURSOR LOCAL FOR
SELECT DISTINCT i.schedule_uid
FROM inserted i
WHERE
((i.execution_mode & 4) = 4) AND
NOT EXISTS (SELECT *
FROM msdb.dbo.syspolicy_policies p
WHERE
p.schedule_uid = i.schedule_uid AND
((p.execution_mode & 4) = 4) AND
p.job_id IS NOT NULL)
-- iterate through the cursor and create a job for every schedule
OPEN schedule_cursor
FETCH schedule_cursor INTO @schedule_uid
WHILE @@FETCH_STATUS = 0
BEGIN
-- figure out if the job is enabled or not
SELECT @is_enabled = COUNT(*)
FROM inserted i
WHERE i.schedule_uid = @schedule_uid AND i.is_enabled = 1
-- create the job that is going to execute the schedule
EXEC [msdb].[dbo].[sp_syspolicy_create_job] @schedule_uid, @is_enabled, @jobID OUTPUT
-- update the job_id back into the policies table
UPDATE p SET p.job_id = @jobID
FROM msdb.dbo.syspolicy_policies_internal p
INNER JOIN inserted i ON p.policy_id = i.policy_id
WHERE
i.schedule_uid = @schedule_uid AND
(i.execution_mode & 4) = 4
FETCH schedule_cursor INTO @schedule_uid
END
CLOSE schedule_cursor
DEALLOCATE schedule_cursor
-- in case we haven't created the job we still need to update
-- the policies with their jobID
UPDATE p
SET p.job_id = ( SELECT TOP 1 p2.job_id
FROM msdb.dbo.syspolicy_policies p2
WHERE
p2.schedule_uid = p.schedule_uid AND
p2.job_id IS NOT NULL)
FROM msdb.dbo.syspolicy_policies p
INNER JOIN inserted i ON p.policy_id = i.policy_id
WHERE
((p.execution_mode & 4) = 4) AND
p.job_id IS NULL
-- if the execution_mode has changed then we need to clear the job references
UPDATE p
SET p.job_id = NULL
FROM msdb.dbo.syspolicy_policies_internal p
INNER JOIN inserted i ON p.policy_id = i.policy_id
INNER JOIN deleted d ON p.policy_id = d.policy_id
WHERE
((i.execution_mode & 4) != 4) AND
((d.execution_mode & 4) = 4) AND
p.job_id IS NOT NULL
-- See what jobs we need to enable.
-- This can happen because we might create a new policy that
-- is enabled and there is already a job for it, but the existing
-- job is disabled
DECLARE jobs_to_enable CURSOR LOCAL FOR
SELECT DISTINCT j.job_id
FROM dbo.sysjobs_view j
JOIN msdb.dbo.syspolicy_policies p ON p.job_id = j.job_id
JOIN inserted i ON p.policy_id = i.policy_id
WHERE
((i.execution_mode & 4) = 4) AND
j.enabled = 0 AND
EXISTS ( SELECT * from msdb.dbo.syspolicy_policies p2
WHERE p2.job_id = j.job_id AND p2.is_enabled = 1)
OPEN jobs_to_enable
FETCH jobs_to_enable INTO @jobID
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC msdb.dbo.sp_update_job @job_id = @jobID, @enabled = 1
FETCH jobs_to_enable INTO @jobID
END
CLOSE jobs_to_enable
DEALLOCATE jobs_to_enable
-- Find out what jobs have to be deleted because the policy's schedule
-- has changed
IF (UPDATE(schedule_uid))
BEGIN
DECLARE deleted_cursor CURSOR LOCAL FOR
SELECT DISTINCT d.job_id
FROM deleted d
WHERE
((d.execution_mode & 4) = 4) AND
d.job_id NOT IN (SELECT job_id FROM msdb.dbo.syspolicy_policies p
WHERE
((p.execution_mode & 4) = 4))
OPEN deleted_cursor
FETCH deleted_cursor INTO @jobID
WHILE (@@FETCH_STATUS=0)
BEGIN
-- delete the job(s), but do not delete the shared schedule
IF (@jobID IS NOT NULL)
EXEC msdb.dbo.sp_delete_job @job_id = @jobID, @delete_unused_schedule = 0
FETCH deleted_cursor INTO @jobID
END -- while (@@FETCH_STATUS=0)
CLOSE deleted_cursor
DEALLOCATE deleted_cursor
END -- UPDATE(schedule_uid)
-- See what jobs we need to disable.
-- This can happen because we do not need to delete the job, but
-- all policies that reference it are disabled.
DECLARE jobs_to_disable CURSOR LOCAL FOR
SELECT DISTINCT j.job_id
FROM dbo.sysjobs_view j
JOIN msdb.dbo.syspolicy_policies p ON p.job_id = j.job_id
WHERE
j.enabled = 1 AND
NOT EXISTS ( SELECT * from msdb.dbo.syspolicy_policies p2
WHERE p2.job_id = j.job_id AND p2.is_enabled = 1 AND ((p2.execution_mode & 4) = 4))
OPEN jobs_to_disable
FETCH jobs_to_disable INTO @jobID
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC msdb.dbo.sp_update_job @job_id = @jobID, @enabled = 0
FETCH jobs_to_disable INTO @jobID
END
CLOSE jobs_to_disable
DEALLOCATE jobs_to_disable
UPDATE msdb.dbo.syspolicy_policies_internal
SET modified_by = original_login(),
date_modified = GETDATE()
FROM inserted i,
msdb.dbo.syspolicy_policies_internal policies
WHERE i.policy_id = policies.policy_id
END -- update trigger
GO
PRINT 'Creating trigger [dbo].[syspolicy_insert_policy_trigger] on [dbo].[syspolicy_policies_internal]'
GO
CREATE TRIGGER [dbo].[syspolicy_insert_policy_trigger] on [dbo].[syspolicy_policies_internal]
FOR INSERT
AS
BEGIN
DECLARE @object_set_id int, @name sysname
SELECT TOP 1 @object_set_id = i.object_set_id, @name = i.name
FROM inserted i
WHERE 1 < (SELECT count(*) FROM syspolicy_policies p WHERE p.object_set_id = i.object_set_id)
IF @@ROWCOUNT > 0
BEGIN
DECLARE @os_name sysname, @policy_name sysname
SELECT TOP 1 @os_name = os.object_set_name, @policy_name = p.name
FROM syspolicy_object_sets os
INNER JOIN syspolicy_policies p ON (os.object_set_id = p.object_set_id)
WHERE os.object_set_id = @object_set_id AND p.name <> @name
RAISERROR(34013, -1, -1, 'ObjectSet', @os_name, @policy_name)
ROLLBACK TRANSACTION
END
END
GO
PRINT 'Creating trigger [dbo].[syspolicy_update_policy_trigger] on [dbo].[syspolicy_policies_internal]'
GO
CREATE TRIGGER [dbo].[syspolicy_update_policy_trigger] on [dbo].[syspolicy_policies_internal]
FOR UPDATE
AS
BEGIN
-- Protect against non-scheduled enabled policies that have scripts in their conditions
IF( UPDATE(is_enabled) )
BEGIN
DECLARE @row_count int
SELECT @row_count = count(*)
FROM syspolicy_conditions c
INNER JOIN inserted i ON (i.condition_id = c.condition_id OR i.root_condition_id = c.condition_id)
WHERE i.is_enabled != 0 AND
i.execution_mode != 4 AND
(1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) )
OPTION (FORCE ORDER)
SELECT @row_count = @row_count + count(*)
FROM dbo.syspolicy_target_set_levels l
INNER JOIN dbo.syspolicy_target_sets s ON s.target_set_id = l.target_set_id
INNER JOIN syspolicy_conditions c on c.condition_id = l.condition_id
INNER JOIN syspolicy_object_sets_internal os on os.object_set_id = s.object_set_id
INNER JOIN inserted i ON os.object_set_id = i.object_set_id
WHERE i.is_enabled != 0 AND
i.execution_mode != 4 AND
(1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) )
OPTION (FORCE ORDER)
IF (@row_count > 0)
BEGIN
RAISERROR(34017, -1, -1)
ROLLBACK TRANSACTION
END
END
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
-- This is to prevent indirect execution of the trigger
IF (TRIGGER_NESTLEVEL() > 1) RETURN
IF( UPDATE(condition_id) )
BEGIN
-- delete all health state records for active policies whose
-- condition has changed
DELETE FROM [dbo].[syspolicy_system_health_state_internal]
FROM [dbo].[syspolicy_system_health_state_internal] phs
INNER JOIN inserted i ON phs.policy_id = i.policy_id
INNER JOIN deleted d ON phs.policy_id = d.policy_id
WHERE d.condition_id != i.condition_id AND i.is_enabled = 1
END
IF( UPDATE(object_set_id) )
BEGIN
DECLARE @object_set_id int, @numref int, @new_object_set_id int, @name sysname
DECLARE os_cursor CURSOR LOCAL FOR
SELECT i.object_set_id, d.object_set_id, i.name
FROM inserted i INNER JOIN deleted d ON (i.policy_id = d.policy_id)
WHERE (d.object_set_id IS NOT NULL AND i.object_set_id IS NULL)
OR (i.object_set_id IS NOT NULL AND d.object_set_id IS NULL)
OR (d.object_set_id != i.object_set_id)
OPEN os_cursor
FETCH os_cursor INTO @new_object_set_id, @object_set_id, @name
WHILE @@FETCH_STATUS = 0
BEGIN
IF (@object_set_id IS NOT NULL)
BEGIN
EXEC sp_syspolicy_verify_object_set_references @object_set_id, @numref OUTPUT
IF (@numref = 0)
EXEC sp_syspolicy_delete_object_set @object_set_id=@object_set_id
END
IF (@new_object_set_id IS NOT NULL)
BEGIN
EXEC sp_syspolicy_verify_object_set_references @new_object_set_id, @numref OUTPUT
IF (@numref > 1)
BEGIN
DECLARE @os_name sysname, @policy_name sysname
SELECT TOP 1 @os_name = os.object_set_name, @policy_name = p.name
FROM syspolicy_object_sets os
INNER JOIN syspolicy_policies p ON (os.object_set_id = p.object_set_id)
WHERE os.object_set_id = @object_set_id AND p.name <> @name
RAISERROR(34013, -1, -1, 'ObjectSet', @os_name, @policy_name)
ROLLBACK TRANSACTION
END
END
FETCH os_cursor INTO @new_object_set_id, @object_set_id, @name
END
CLOSE os_cursor
DEALLOCATE os_cursor
END
IF( UPDATE(is_enabled) )
BEGIN
-- delete all health state records for policies that
-- have been disabled
DELETE FROM [dbo].[syspolicy_system_health_state_internal]
FROM [dbo].[syspolicy_system_health_state_internal] phs
INNER JOIN inserted i ON phs.policy_id = i.policy_id
INNER JOIN deleted d ON phs.policy_id = d.policy_id
WHERE d.is_enabled = 1 AND i.is_enabled = 0
END
END
GO
PRINT 'Creating trigger [dbo].[syspolicy_delete_job_delete_trigger] on [dbo].[syspolicy_policies_internal]'
GO
CREATE TRIGGER [dbo].[syspolicy_delete_job_delete_trigger] on [dbo].[syspolicy_policies_internal]
FOR DELETE
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
DECLARE @jobID uniqueidentifier
-- Declare the cursor to iterate over the jobs that are only referenced
-- by deleted policies. The jobs that are still referenced by active policies
-- should not be deleted.
DECLARE deleted_cursor CURSOR LOCAL FOR
SELECT DISTINCT d.job_id
FROM deleted d
WHERE
((d.execution_mode & 4) = 4) AND
NOT EXISTS (SELECT * FROM msdb.dbo.syspolicy_policies p
WHERE
p.job_id = d.job_id AND
((p.execution_mode & 4) = 4) AND
p.policy_id NOT IN (SELECT d2.policy_id FROM deleted d2))
OPEN deleted_cursor
FETCH deleted_cursor INTO @jobID
WHILE (@@FETCH_STATUS=0)
BEGIN
-- delete the job(s), but do not delete the shared schedule
IF (@jobID IS NOT NULL)
EXEC msdb.dbo.sp_delete_job @job_id = @jobID, @delete_unused_schedule = 0
FETCH deleted_cursor INTO @jobID
END -- while (@@FETCH_STATUS=0)
CLOSE deleted_cursor
DEALLOCATE deleted_cursor
-- See what jobs we need to disable.
-- This can happen because we do not need to delete the job, but
-- all policies that reference it are disabled.
DECLARE jobs_to_disable CURSOR LOCAL FOR
SELECT DISTINCT j.job_id
FROM dbo.sysjobs_view j
JOIN deleted d ON d.job_id = j.job_id
WHERE
j.enabled = 1 AND
NOT EXISTS ( SELECT * from msdb.dbo.syspolicy_policies p2
WHERE p2.job_id = j.job_id AND p2.is_enabled = 1 AND ((p2.execution_mode & 4) = 4))
OPEN jobs_to_disable
FETCH jobs_to_disable INTO @jobID
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC msdb.dbo.sp_update_job @job_id = @jobID, @enabled = 0
FETCH jobs_to_disable INTO @jobID
END
CLOSE jobs_to_disable
DEALLOCATE jobs_to_disable
-- update eventing infrastructure
IF EXISTS ( SELECT * FROM deleted d WHERE ((d.execution_mode & 1) = 1))
BEGIN
EXEC sys.sp_syspolicy_update_ddl_trigger
END
IF EXISTS (SELECT * FROM deleted d WHERE ((d.execution_mode & 2) = 2))
BEGIN
EXEC sys.sp_syspolicy_update_event_notification
END
END
GO
PRINT 'Creating trigger [dbo].[syspolicy_instead_delete_policy_trigger] on [dbo].[syspolicy_policies_internal]'
GO
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- when changing logic in this trigger, please remember to change the logic in #sp_syspolicy_cascade_delete_policy of alwayson.sql
-------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE TRIGGER [dbo].[syspolicy_instead_delete_policy_trigger] on [dbo].[syspolicy_policies_internal]
INSTEAD OF DELETE
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
-- This trigger deletes references in given order to protect from deadlocks
DELETE msdb.dbo.syspolicy_policy_execution_history_internal WHERE policy_id in (SELECT policy_id FROM deleted)
DELETE msdb.dbo.syspolicy_system_health_state_internal WHERE policy_id in (SELECT policy_id FROM deleted)
DELETE msdb.dbo.syspolicy_policies_internal WHERE policy_id in (SELECT policy_id FROM deleted)
END
GO
PRINT 'Creating view [dbo].[syspolicy_policies]...'
GO
CREATE VIEW [dbo].[syspolicy_policies]
AS
SELECT
policy_id,
name,
condition_id,
root_condition_id,
date_created,
execution_mode,
policy_category_id,
schedule_uid,
description,
help_text,
help_link,
object_set_id,
is_enabled,
job_id,
created_by,
modified_by,
date_modified,
is_system
FROM [dbo].[syspolicy_policies_internal]
GO
PRINT ''
PRINT 'Creating trigger syspolicy_insert_condition_trigger...'
GO
CREATE TRIGGER dbo.syspolicy_insert_condition_trigger
ON msdb.dbo.syspolicy_conditions_internal
AFTER INSERT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
UPDATE msdb.dbo.syspolicy_conditions_internal
SET created_by = original_login()
FROM inserted i INNER JOIN
msdb.dbo.syspolicy_conditions_internal conditions
ON i.condition_id = conditions.condition_id
END
GO
PRINT ''
PRINT 'Creating trigger dbo.syspolicy_for_update_condition_trigger...'
GO
CREATE TRIGGER dbo.syspolicy_for_update_condition_trigger
ON msdb.dbo.syspolicy_conditions_internal
FOR UPDATE
AS
BEGIN
-- do not allow expression to be changed to a script
-- if the policy is enabled
IF UPDATE(expression)
BEGIN
DECLARE @row_count int
SELECT @row_count = count(*)
FROM inserted i
INNER JOIN syspolicy_policies p ON (i.condition_id = p.condition_id OR p.root_condition_id = i.condition_id)
WHERE p.is_enabled != 0 AND
p.execution_mode != 4 AND
(1 = CONVERT(xml, i.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
1 = CONVERT(xml, i.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) )
OPTION (FORCE ORDER)
SELECT @row_count = @row_count + count(*)
FROM dbo.syspolicy_target_set_levels l
INNER JOIN dbo.syspolicy_target_sets s ON s.target_set_id = l.target_set_id
INNER JOIN inserted i on i.condition_id = l.condition_id
INNER JOIN syspolicy_object_sets_internal os ON s.object_set_id = os.object_set_id
INNER JOIN syspolicy_policies p ON os.object_set_id = p.object_set_id
WHERE p.is_enabled != 0 AND
p.execution_mode != 4 AND
(1 = CONVERT(xml, i.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
1 = CONVERT(xml, i.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) )
OPTION (FORCE ORDER)
IF (@row_count > 0)
BEGIN
RAISERROR(34017, -1, -1)
ROLLBACK TRANSACTION
END
END
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
-- This is to prevent indirect entrance of the trigger
IF (TRIGGER_NESTLEVEL() > 1)
RETURN
END
GO
PRINT ''
PRINT 'Creating trigger syspolicy_after_update_condition_trigger...'
GO
CREATE TRIGGER dbo.syspolicy_after_update_condition_trigger
ON msdb.dbo.syspolicy_conditions_internal
AFTER UPDATE
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
-- This is to prevent indirect entrance of the trigger
IF (TRIGGER_NESTLEVEL() > 1)
RETURN
UPDATE msdb.dbo.syspolicy_conditions_internal
SET modified_by = original_login(), date_modified = GETDATE()
FROM inserted i
INNER JOIN msdb.dbo.syspolicy_conditions_internal c ON i.condition_id = c.condition_id
-- update health state table by deleting all the records for
-- policies whose expression has been modified
IF UPDATE(expression)
BEGIN
DELETE FROM dbo.syspolicy_system_health_state_internal
FROM dbo.syspolicy_system_health_state_internal phs
INNER JOIN dbo.syspolicy_policies p ON phs.policy_id = p.policy_id
INNER JOIN inserted i ON p.condition_id = i.condition_id
INNER JOIN deleted d ON p.condition_id = d.condition_id
WHERE d.expression != i.expression
END
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_verify_policy_category_identifiers]...'
GO
-----------------------------------------------------------
-- This procedure verifies if a policy category exists
-- The caller can pass either the policy category name or the id
-----------------------------------------------------------
CREATE PROCEDURE [dbo].[sp_syspolicy_verify_policy_category_identifiers]
@policy_category_name sysname = NULL OUTPUT,
@policy_category_id int = NULL OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
IF ((@policy_category_name IS NULL) AND (@policy_category_id IS NULL)) OR
((@policy_category_name IS NOT NULL) AND (@policy_category_id IS NOT NULL))
BEGIN
RAISERROR(14524, -1, -1, '@policy_category_name', '@policy_category_id')
RETURN(1) -- Failure
END
-- Check id
IF (@policy_category_id IS NOT NULL)
BEGIN
SELECT @policy_category_name = name
FROM msdb.dbo.syspolicy_policy_categories
WHERE (policy_category_id = @policy_category_id)
-- the view would take care of all the permissions issues.
IF (@policy_category_name IS NULL)
BEGIN
DECLARE @policy_category_id_as_char VARCHAR(36)
SELECT @policy_category_id_as_char = CONVERT(VARCHAR(36), @policy_category_id)
RAISERROR(14262, -1, -1, '@policy_category_id', @policy_category_id_as_char)
RETURN(1) -- Failure
END
END
ELSE
-- Check name
IF (@policy_category_name IS NOT NULL)
BEGIN
-- get the corresponding policy_category_id (if the condition exists)
SELECT @policy_category_id = policy_category_id
FROM msdb.dbo.syspolicy_policy_categories
WHERE (name = @policy_category_name)
-- the view would take care of all the permissions issues.
IF (@policy_category_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@policy_category_name', @policy_category_name)
RETURN(1) -- Failure
END
END
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_add_policy_category]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_policy_category]
@name sysname,
@mandate_database_subscriptions bit = 1,
@policy_category_id int OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
DECLARE @null_column sysname
SET @null_column = NULL
IF(@name IS NULL OR @name = N'')
SET @null_column = '@name'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_syspolicy_add_policy_category')
RETURN(1)
END
IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_policy_categories_internal WHERE name = @name)
BEGIN
RAISERROR(34010, -1, -1, 'Policy Category', @name)
RETURN(1)
END
INSERT INTO msdb.dbo.syspolicy_policy_categories_internal(name, mandate_database_subscriptions) VALUES (@name, @mandate_database_subscriptions)
SELECT @retval = @@error
SET @policy_category_id = SCOPE_IDENTITY()
RETURN(@retval)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_policy_category]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_policy_category]
@name sysname = NULL,
@policy_category_id int = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
EXEC @retval = sp_syspolicy_verify_policy_category_identifiers @name, @policy_category_id OUTPUT
IF (@retval <> 0)
RETURN (1)
IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_policy_category_subscriptions WHERE policy_category_id = @policy_category_id)
BEGIN
RAISERROR(34012,-1,-1,'Policy Category','Policy Subscription')
RETURN (1)
END
IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_policies WHERE policy_category_id = @policy_category_id)
BEGIN
RAISERROR(34012,-1,-1,'Policy Category','Policy')
RETURN (1)
END
DELETE msdb.dbo.syspolicy_policy_categories_internal
WHERE policy_category_id = @policy_category_id
SET @retval = @@error
RETURN @retval
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_rename_policy_category]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_rename_policy_category]
@name sysname = NULL,
@policy_category_id int = NULL,
@new_name sysname = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
IF (@new_name IS NULL or LEN(@new_name) = 0)
BEGIN
RAISERROR(21263, -1, -1, '@new_name')
RETURN(1) -- Failure
END
DECLARE @retval INT
EXEC @retval = sp_syspolicy_verify_policy_category_identifiers @name, @policy_category_id OUTPUT
IF (@retval <> 0)
RETURN (1)
UPDATE msdb.[dbo].[syspolicy_policy_categories_internal ]
SET name = @new_name
WHERE policy_category_id = @policy_category_id
SELECT @retval = @@error
RETURN(@retval)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_update_policy_category]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_policy_category]
@name sysname = NULL,
@policy_category_id int = NULL,
@mandate_database_subscriptions bit = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
EXEC @retval = sp_syspolicy_verify_policy_category_identifiers @name, @policy_category_id OUTPUT
IF (@retval <> 0)
RETURN (1)
UPDATE msdb.[dbo].[syspolicy_policy_categories_internal ]
SET mandate_database_subscriptions = ISNULL(@mandate_database_subscriptions, mandate_database_subscriptions)
WHERE policy_category_id = @policy_category_id
SELECT @retval = @@error
RETURN(@retval)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_add_policy]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_policy]
@name sysname,
@condition_id int = NULL,
@condition_name sysname = NULL,
@schedule_uid uniqueidentifier = NULL,
@policy_category sysname = NULL,
@description nvarchar(max) = N'',
@help_text nvarchar(4000) = N'',
@help_link nvarchar(2083) = N'',
@execution_mode int,
@is_enabled bit = 0,
@root_condition_id int = NULL,
@root_condition_name sysname = NULL,
@object_set sysname = NULL,
@policy_id int = NULL OUTPUT
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
DECLARE @null_column sysname
SET @null_column = NULL
IF (@name IS NULL OR @name = N'')
SET @null_column = '@name'
ELSE IF (@execution_mode IS NULL )
SET @null_column = '@execution_mode'
ELSE IF( @is_enabled IS NULL)
SET @null_column = '@is_enabled'
ELSE IF( @description IS NULL)
SET @null_column = '@description'
ELSE IF( @help_text IS NULL)
SET @null_column = '@help_text'
ELSE IF( @help_link IS NULL)
SET @null_column = '@help_link'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_syspolicy_add_policy')
RETURN(1)
END
IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_policies WHERE name = @name)
BEGIN
RAISERROR(34010, -1, -1, 'Policy', @name)
RETURN(1)
END
SET @schedule_uid = ISNULL (@schedule_uid, '{00000000-0000-0000-0000-000000000000}')
--Check for the execution mode value
IF (@execution_mode NOT IN (0,1,2,4,5,6))
BEGIN
RAISERROR(34004, -1, -1, @execution_mode)
RETURN (1)
END
IF (@schedule_uid = '{00000000-0000-0000-0000-000000000000}' AND (@execution_mode & 4) = 4)
BEGIN
RAISERROR (34011, -1, -1, 'schedule_uid', 4)
RETURN(1)
END
IF (@is_enabled = 1 AND @execution_mode = 0)
BEGIN
RAISERROR (34011, -1, -1, 'is_enabled', @execution_mode)
RETURN(1)
END
-- Turn [nullable] empty string parameters into NULLs
IF @condition_name = '' SELECT @condition_name = NULL
IF @policy_category = '' SELECT @policy_category = NULL
IF @root_condition_name = '' SELECT @root_condition_name = NULL
-- verify that the condition exists
EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @condition_name OUTPUT, @condition_id = @condition_id OUTPUT
IF (@retval <> 0)
RETURN(1)
-- convert @object_set into id if needed
DECLARE @object_set_id INT
DECLARE @object_set_facet_id INT
IF (@object_set IS NOT NULL)
BEGIN
SELECT @object_set_id = object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name = @object_set
IF @object_set_id IS NULL
BEGIN
-- TODO: RAISERROR that specified object set doesn't exist
RAISERROR(N'specified object set does not exists', -1, -1)
RETURN(1) -- Failure
END
ELSE
BEGIN
SELECT @object_set_facet_id = facet_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name = @object_set
-- Ensure the object set has been created from the same facet that the policy condition has been created
IF (@object_set_facet_id <> (SELECT facet_id FROM msdb.dbo.syspolicy_conditions_internal WHERE condition_id = @condition_id))
BEGIN
-- TODO: RAISEERROR that specified object_set isn't created from the facet that the policy condition has been created from
RAISERROR(N'specified object set does not match facet the policy condition was created off', -1, -1)
RETURN(1) -- Failure
END
END
END
IF (@root_condition_name IS NOT NULL) OR (@root_condition_id IS NOT NULL)
BEGIN
-- verify that the root condition exists
EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @root_condition_name OUTPUT, @condition_id = @root_condition_id OUTPUT
IF (@retval <> 0)
RETURN(1)
-- Check execution mode for compatibility with root_condition
IF (@execution_mode = 1) OR (@execution_mode = 2) -- Enforce or Check on Change
BEGIN
RAISERROR (34011, -1, -1, 'root_condition', @execution_mode)
RETURN(1)
END
END
-- verify schedule
IF (@schedule_uid != '{00000000-0000-0000-0000-000000000000}')
BEGIN
IF NOT EXISTS (SELECT * FROM msdb.dbo.sysschedules WHERE schedule_uid = @schedule_uid)
BEGIN
RAISERROR(14365, -1, -1)
RETURN(1) -- Failure
END
END
-- convert group_name into id if needed
DECLARE @policy_category_id INT
IF ( (@policy_category IS NOT NULL) )
BEGIN
IF NOT EXISTS (SELECT * from msdb.dbo.syspolicy_policy_categories WHERE name = @policy_category)
BEGIN
RAISERROR(34015, -1, -1,@policy_category)
RETURN(1) -- Failure
END
ELSE
SELECT @policy_category_id = policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name = @policy_category
END
INSERT INTO msdb.dbo.syspolicy_policies_internal
(name,
execution_mode,
schedule_uid,
policy_category_id,
description,
help_text,
help_link,
condition_id,
root_condition_id,
object_set_id,
is_enabled)
VALUES
(@name,
@execution_mode,
@schedule_uid,
@policy_category_id,
@description,
@help_text,
@help_link,
@condition_id,
@root_condition_id,
@object_set_id,
@is_enabled)
SELECT @retval = @@error
SET @policy_id = SCOPE_IDENTITY()
RETURN(@retval)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_verify_policy_identifiers]...'
GO
-----------------------------------------------------------
-- This procedure verifies if a policy definition exists
-- The caller can pass either the name or the id
-----------------------------------------------------------
CREATE PROCEDURE [dbo].[sp_syspolicy_verify_policy_identifiers]
@name sysname = NULL OUTPUT,
@policy_id int = NULL OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
IF ((@name IS NULL) AND (@policy_id IS NULL)) OR
((@name IS NOT NULL) AND (@policy_id IS NOT NULL))
BEGIN
RAISERROR(14524, -1, -1, '@name', '@policy_id')
RETURN(1) -- Failure
END
-- Check id
IF (@policy_id IS NOT NULL)
BEGIN
SELECT @name = name
FROM msdb.dbo.syspolicy_policies
WHERE (policy_id = @policy_id)
-- the view would take care of all the permissions issues.
IF (@name IS NULL)
BEGIN
DECLARE @policy_id_as_char VARCHAR(36)
SELECT @policy_id_as_char = CONVERT(VARCHAR(36), @policy_id)
RAISERROR(14262, -1, -1, '@policy_id', @policy_id_as_char)
RETURN(1) -- Failure
END
END
ELSE
-- Check name
IF (@name IS NOT NULL)
BEGIN
-- get the corresponding policy_id (if the policy exists)
SELECT @policy_id = policy_id
FROM msdb.dbo.syspolicy_policies
WHERE (name = @name)
-- the view would take care of all the permissions issues.
IF (@policy_id IS NULL)
BEGIN
RAISERROR(14262, -1, -1, '@name', @name)
RETURN(1) -- Failure
END
END
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_rename_policy]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_rename_policy]
@name sysname = NULL,
@policy_id int = NULL,
@new_name sysname = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
IF (@new_name IS NULL or LEN(@new_name) = 0)
BEGIN
RAISERROR(21263, -1, -1, '@new_name')
RETURN(1) -- Failure
END
DECLARE @retval INT
EXEC @retval = sp_syspolicy_verify_policy_identifiers @name, @policy_id OUTPUT
IF (@retval <> 0)
RETURN (1)
UPDATE msdb.[dbo].[syspolicy_policies_internal]
SET name = @new_name
WHERE policy_id = @policy_id
SELECT @retval = @@error
RETURN(@retval)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_update_policy]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_policy]
@name sysname = NULL,
@policy_id int = NULL,
@condition_id int=NULL,
@condition_name sysname = NULL,
@execution_mode int=NULL,
@policy_category sysname = NULL,
@schedule_uid uniqueidentifier = NULL,
@description nvarchar(max) = NULL,
@help_text nvarchar(4000) = NULL,
@help_link nvarchar(2083) = NULL,
@root_condition_id int = -1,
@root_condition_name sysname = NULL,
@object_set_id int = -1,
@object_set sysname = NULL,
@is_enabled bit = NULL
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
--Check for the execution mode value
IF (((@execution_mode IS NOT NULL)) AND (@execution_mode NOT IN (0,1,2,4,5,6)))
BEGIN
RAISERROR(34004, -1, -1, @execution_mode)
RETURN (1)
END
-- Turn [nullable] empty string parameters into NULLs
IF @name = '' SELECT @name = NULL
IF @condition_name = '' SELECT @condition_name = NULL
IF @root_condition_name = ''
BEGIN
SELECT @root_condition_name = NULL
IF @root_condition_id = -1
-- root_condition is being reset
SELECT @root_condition_id = NULL
END
IF @object_set = ''
BEGIN
SELECT @object_set = NULL
IF @object_set_id = -1
-- object_set is being reset
SELECT @object_set_id = NULL
END
DECLARE @retval INT
EXEC @retval = msdb.dbo.sp_syspolicy_verify_policy_identifiers @name, @policy_id OUTPUT
IF (@retval <> 0)
RETURN (1)
SELECT @execution_mode = ISNULL(@execution_mode, execution_mode),
@is_enabled = ISNULL(@is_enabled, is_enabled)
FROM msdb.dbo.syspolicy_policies WHERE policy_id = @policy_id
IF(@condition_id IS NOT NULL or @condition_name IS NOT NULL)
BEGIN
EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @condition_name OUTPUT, @condition_id = @condition_id OUTPUT
IF (@retval <> 0)
RETURN (1)
END
IF((@root_condition_id IS NOT NULL and @root_condition_id != -1) or @root_condition_name IS NOT NULL)
BEGIN
IF (@root_condition_id = -1 and @root_condition_name IS NOT NULL)
SET @root_condition_id = NULL
EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @root_condition_name OUTPUT, @condition_id = @root_condition_id OUTPUT
IF (@retval <> 0)
RETURN (1)
END
SET @schedule_uid = ISNULL (@schedule_uid, '{00000000-0000-0000-0000-000000000000}')
IF (@schedule_uid = '{00000000-0000-0000-0000-000000000000}' AND (@execution_mode & 4) = 4)
BEGIN
RAISERROR (34011, -1, -1, 'schedule_uid', 4)
RETURN(1)
END
IF (@is_enabled = 1 AND @execution_mode = 0)
BEGIN
RAISERROR (34011, -1, -1, 'is_enabled', @execution_mode)
RETURN(1)
END
IF (@schedule_uid != '{00000000-0000-0000-0000-000000000000}')
BEGIN
-- verify the schedule exists
IF NOT EXISTS (SELECT schedule_id FROM msdb.dbo.sysschedules WHERE schedule_uid = @schedule_uid)
BEGIN
RAISERROR (14365, -1, -1)
RETURN(1)
END
END
DECLARE @object_set_facet_id INT
IF ((@object_set_id IS NOT NULL and @object_set_id != -1) or @object_set IS NOT NULL)
BEGIN
IF (@object_set_id = -1 and @object_set IS NOT NULL)
SET @object_set_id = NULL
EXEC @retval = msdb.dbo.sp_syspolicy_verify_object_set_identifiers @name = @object_set OUTPUT, @object_set_id = @object_set_id OUTPUT
IF (@retval <> 0)
RETURN (1)
SELECT @object_set_facet_id = facet_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name = @object_set
-- Ensure the object set has been created from the same facet that the policy condition has been created
IF (@object_set_facet_id <> (SELECT facet_id FROM msdb.dbo.syspolicy_conditions_internal WHERE condition_id = @condition_id))
BEGIN
-- TODO: RAISEERROR that specified object_set isn't created from the facet that the policy condition has been created from
RAISERROR(N'specified object set does not match facet the policy condition was created off', -1, -1)
RETURN(1) -- Failure
END
END
DECLARE @policy_category_id INT
SET @policy_category_id = NULL
BEGIN TRANSACTION
DECLARE @old_policy_category_id INT
SELECT @old_policy_category_id = policy_category_id
FROM syspolicy_policies
WHERE policy_id = @policy_id
IF ( (@policy_category IS NOT NULL and @policy_category != '') )
BEGIN
IF NOT EXISTS (SELECT * from syspolicy_policy_categories WHERE name = @policy_category)
BEGIN
RAISERROR(34015, -1, -1,@policy_category)
RETURN(1) -- Failure
END
ELSE
SELECT @policy_category_id = policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name = @policy_category
END
-- If the caller gave us an empty string for the
-- @policy_category, then that means to remove the group.
DECLARE @new_policy_category_id INT
SELECT @new_policy_category_id = @old_policy_category_id
IF ( (@policy_category = '') )
SELECT @new_policy_category_id = NULL
ELSE IF (@policy_category_id IS NOT NULL)
SELECT @new_policy_category_id = @policy_category_id
UPDATE msdb.dbo.syspolicy_policies_internal
SET
condition_id = ISNULL(@condition_id, condition_id),
root_condition_id = CASE @root_condition_id WHEN -1 THEN root_condition_id ELSE @root_condition_id END,
execution_mode = ISNULL(@execution_mode, execution_mode ),
schedule_uid = @schedule_uid,
policy_category_id = @new_policy_category_id,
description = ISNULL(@description, description),
help_text = ISNULL(@help_text, help_text),
help_link = ISNULL(@help_link, help_link),
is_enabled = ISNULL(@is_enabled, is_enabled),
object_set_id = CASE @object_set_id WHEN -1 THEN object_set_id ELSE @object_set_id END
WHERE policy_id = @policy_id
COMMIT TRANSACTION
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_policy]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_policy]
@name sysname = NULL,
@policy_id int = NULL
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
EXEC @retval = sp_syspolicy_verify_policy_identifiers @name, @policy_id OUTPUT
IF (@retval <> 0)
RETURN (1)
DELETE msdb.dbo.syspolicy_policies_internal
WHERE policy_id = @policy_id
RETURN (0)
END
GO
IF NOT EXISTS (SELECT * FROM sys.types where name = 'syspolicy_target_filters_type')
BEGIN
PRINT 'Creating type [dbo].[syspolicy_target_filters_type]...'
CREATE TYPE [dbo].[syspolicy_target_filters_type]
AS
TABLE (
target_filter_id int,
policy_id int,
type sysname NOT NULL,
filter nvarchar(max) NOT NULL,
type_skeleton sysname NOT NULL
)
END
GO
PRINT 'Creating function [dbo].[syspolicy_fn_get_bad_filters]...'
GO
-- This function returns filters that are not supported
-- It is used to prevent unsupported filters from being
-- created. It will only reject well formed filters, in
-- other words it will not perform a full syntax check.
CREATE FUNCTION [dbo].[syspolicy_fn_get_bad_filters] (
@inserted [dbo].[syspolicy_target_filters_type] READONLY
)
RETURNS TABLE
AS
RETURN
(
SELECT filter FROM @inserted
WHERE
-- do not accept filters for the next level
filter LIKE N'Server/%/%\[@%=%\]%' ESCAPE '\' AND
-- take out cases when the property contains the pattern
filter NOT LIKE 'Server/%\[%\[%\]%\]%' ESCAPE '\'
)
GO
---------------------------------------------------------------
-- Target Set object
---------------------------------------------------------------
IF OBJECT_ID ('[dbo].[syspolicy_target_sets_internal]') IS NULL
BEGIN
PRINT 'Creating table [dbo].[syspolicy_target_sets_internal]...'
CREATE TABLE [dbo].[syspolicy_target_sets_internal] (
target_set_id int NOT NULL IDENTITY(1,1),
object_set_id int NOT NULL,
type_skeleton nvarchar(440) NOT NULL,
type sysname NOT NULL,
enabled bit NOT NULL,
-- TODO: Verify if the primary access method of this table is based on policy_id then perhaps the clustered intdex should be on the policy id?
CONSTRAINT [PK_syspolicy_target_sets] PRIMARY KEY CLUSTERED (target_set_id),
)
ALTER TABLE [dbo].[syspolicy_target_sets_internal]
ADD CONSTRAINT [FK_syspolicy_target_sets_syspolicy_object_sets] FOREIGN KEY(object_set_id)
REFERENCES [dbo].[syspolicy_object_sets_internal] (object_set_id)
ON DELETE CASCADE
CREATE UNIQUE INDEX [UX_syspolicy_target_sets] ON [dbo].[syspolicy_target_sets_internal](object_set_id, type_skeleton)
END
GO
PRINT 'Creating view [dbo].[syspolicy_target_sets]...'
GO
CREATE VIEW [dbo].[syspolicy_target_sets]
AS
SELECT
target_set_id,
object_set_id,
type_skeleton,
type,
enabled
FROM [dbo].[syspolicy_target_sets_internal]
GO
IF OBJECT_ID ('[dbo].[syspolicy_target_set_levels_internal]') IS NULL
BEGIN
PRINT 'Creating table [dbo].[syspolicy_target_set_levels_internal]...'
CREATE TABLE [dbo].[syspolicy_target_set_levels_internal] (
target_set_level_id int NOT NULL IDENTITY(1,1),
target_set_id int NOT NULL,
type_skeleton nvarchar(440) NOT NULL,
condition_id int NULL,
level_name sysname NOT NULL,
CONSTRAINT [PK_syspolicy_target_set_levels_internal] PRIMARY KEY CLUSTERED (target_set_level_id),
)
ALTER TABLE [dbo].[syspolicy_target_set_levels_internal]
ADD CONSTRAINT [FK_syspolicy_levels_target_sets] FOREIGN KEY(target_set_id)
REFERENCES [dbo].[syspolicy_target_sets_internal] (target_set_id)
ON DELETE CASCADE
ALTER TABLE [dbo].[syspolicy_target_set_levels_internal]
ADD CONSTRAINT [FK_syspolicy_levels_conditions] FOREIGN KEY(condition_id)
REFERENCES [dbo].[syspolicy_conditions_internal] (condition_id)
CREATE UNIQUE INDEX [UX_syspolicy_levels] ON [dbo].[syspolicy_target_sets_internal](target_set_id, type_skeleton)
END
GO
PRINT 'Creating view [dbo].[syspolicy_target_set_levels]...'
GO
CREATE VIEW [dbo].[syspolicy_target_set_levels]
AS
SELECT
target_set_level_id,
target_set_id,
type_skeleton,
condition_id,
level_name
FROM [dbo].[syspolicy_target_set_levels_internal]
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_add_target_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_target_set]
@object_set_id int = NULL,
@object_set_name sysname = NULL,
@type_skeleton nvarchar(max),
@type sysname,
@enabled bit,
@target_set_id int OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
EXEC @retval = dbo.sp_syspolicy_verify_object_set_identifiers @name = @object_set_name OUTPUT, @object_set_id = @object_set_id OUTPUT
if( @retval <> 0)
RETURN(1)
INSERT INTO msdb.[dbo].[syspolicy_target_sets_internal]
(object_set_id,
type_skeleton,
type,
enabled)
VALUES
(@object_set_id,
@type_skeleton,
@type,
@enabled)
SELECT @retval = @@error
SET @target_set_id = SCOPE_IDENTITY()
RETURN(@retval)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_update_target_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_target_set]
@target_set_id int,
@enabled bit
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
UPDATE [msdb].[dbo].[syspolicy_target_sets_internal]
SET
enabled = @enabled
WHERE
target_set_id = @target_set_id
IF (@@ROWCOUNT = 0)
BEGIN
DECLARE @target_set_id_as_char VARCHAR(36)
SELECT @target_set_id_as_char = CONVERT(VARCHAR(36), @target_set_id)
RAISERROR(14262, -1, -1, '@target_set_id', @target_set_id_as_char)
RETURN (1)
END
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_target_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_target_set]
@target_set_id int
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DELETE msdb.[dbo].[syspolicy_target_sets_internal]
WHERE target_set_id = @target_set_id
IF (@@ROWCOUNT = 0)
BEGIN
DECLARE @target_set_id_as_char VARCHAR(36)
SELECT @target_set_id_as_char = CONVERT(VARCHAR(36), @target_set_id)
RAISERROR(14262, -1, -1, '@target_set_id', @target_set_id_as_char)
RETURN (1)
END
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_add_target_set_level]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_target_set_level]
@target_set_id int,
@type_skeleton nvarchar(max),
@condition_id int = NULL,
@condition_name sysname = NULL,
@level_name sysname,
@target_set_level_id int OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval INT
IF NOT EXISTS (SELECT * FROM syspolicy_target_sets WHERE target_set_id = @target_set_id)
RETURN (1)
IF (@condition_name = '')
SET @condition_name = NULL
IF(@condition_id IS NOT NULL or @condition_name IS NOT NULL)
BEGIN
EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @condition_name OUTPUT, @condition_id = @condition_id OUTPUT
IF (@retval <> 0)
RETURN (1)
END
INSERT INTO msdb.[dbo].[syspolicy_target_set_levels_internal]
(target_set_id,
type_skeleton,
condition_id,
level_name)
VALUES
(@target_set_id,
@type_skeleton,
@condition_id,
@level_name)
SELECT @retval = @@error
SET @target_set_level_id = SCOPE_IDENTITY()
RETURN(@retval)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_update_target_set_level]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_target_set_level]
@target_set_id int,
@type_skeleton nvarchar(max),
@condition_id int = NULL,
@condition_name sysname = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval int
IF @condition_name = '' SET @condition_name = NULL
IF(@condition_id IS NOT NULL or @condition_name IS NOT NULL)
BEGIN
EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @condition_name OUTPUT, @condition_id = @condition_id OUTPUT
IF (@retval <> 0)
RETURN (1)
END
UPDATE msdb.[dbo].[syspolicy_target_set_levels_internal]
SET condition_id = @condition_id
WHERE target_set_id = @target_set_id AND type_skeleton = @type_skeleton
IF (@@ROWCOUNT = 0)
BEGIN
DECLARE @id nvarchar(max)
SET @id = '@target_set_id='+LTRIM(STR(@target_set_id))+' @type_skeleton='''+@type_skeleton+''''
RAISERROR(14262, -1, -1, 'Target Set Level', @id)
RETURN (1)
END
RETURN (0)
END
GO
PRINT 'Creating function [dbo].[syspolicy_fn_eventing_filter]'
GO
CREATE FUNCTION [dbo].[syspolicy_fn_eventing_filter] (@target_set_id INT)
RETURNS INT
AS
BEGIN
DECLARE @cnt int, @level sysname, @condition_id int, @ret int
SELECT @cnt = count(*) FROM msdb.dbo.syspolicy_target_set_levels
WHERE target_set_id = @target_set_id AND condition_id IS NOT NULL
IF @cnt = 0
RETURN 1
ELSE IF @cnt > 1
RETURN 0
ELSE
BEGIN
SELECT @level = level_name, @condition_id = condition_id FROM msdb.dbo.syspolicy_target_set_levels
WHERE target_set_id = @target_set_id AND condition_id IS NOT NULL
IF @level != 'Database'
RETURN 0
IF @condition_id IS NOT NULL
BEGIN
IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_conditions
WHERE condition_id = @condition_id AND
(1 = CONVERT(xml, expression).exist('//FunctionType/text()[.="ExecuteSql"]') OR
1 = CONVERT(xml, expression).exist('//FunctionType/text()[.="ExecuteWql"]') ) )
RETURN 0
END
SELECT @ret = is_name_condition
FROM msdb.dbo.syspolicy_conditions
WHERE condition_id = @condition_id
END
RETURN @ret
END
GO
PRINT 'Creating function [dbo].[syspolicy_fn_filter_complete]'
GO
CREATE FUNCTION [dbo].[syspolicy_fn_filter_complete] (@target_set_id INT)
RETURNS INT
AS
BEGIN
DECLARE @target_set_skeleton nvarchar(max), @skeleton nvarchar(max), @level sysname, @dummy nvarchar(max), @ret int,
@i int, @p int
SELECT @target_set_skeleton = type_skeleton, @i=0, @p=CHARINDEX('/',type_skeleton)
FROM msdb.dbo.syspolicy_target_sets
WHERE target_set_id = @target_set_id
IF @@ROWCOUNT != 1 RETURN 0
IF @target_set_skeleton = 'Server' RETURN 1
-- Count the number of levels in the skeleton past the root
WHILE (@p <> 0)
BEGIN
SET @i = @i + 1
SET @p = CHARINDEX('/', @target_set_skeleton, @p + 1)
END
-- Compare the number of levels in the skeleton with those in TSL
IF (@i = (SELECT COUNT(*) FROM msdb.dbo.syspolicy_target_set_levels
WHERE target_set_id = @target_set_id))
RETURN 1
RETURN 0
END
GO
PRINT 'Creating trigger [dbo].[syspolicy_insert_target_set_level_trigger] on [dbo].[syspolicy_target_set_levels_internal]'
GO
CREATE TRIGGER [dbo].[syspolicy_insert_target_set_level_trigger]
ON [dbo].[syspolicy_target_set_levels_internal]
FOR INSERT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
DECLARE @update_notifications INT
DECLARE @update_ddl_trigger INT
SET @update_notifications = 0
SET @update_ddl_trigger = 0
DECLARE @level sysname
SET @level = NULL
-- Don't allow setting non-db levels for runtime policies
SELECT TOP 1 @level = i.level_name
FROM inserted i
JOIN dbo.syspolicy_target_sets s ON (i.target_set_id = s.target_set_id)
JOIN msdb.dbo.syspolicy_object_sets os ON s.object_set_id = os.object_set_id
JOIN msdb.dbo.syspolicy_policies p ON (os.object_set_id = p.object_set_id)
WHERE 1 = dbo.syspolicy_fn_filter_complete (i.target_set_id) AND
((p.execution_mode & 3) > 0 AND 0 = dbo.syspolicy_fn_eventing_filter (i.target_set_id))
IF @level IS NOT NULL
BEGIN
RAISERROR(34016, -1, -1, @level)
ROLLBACK TRANSACTION
END
SELECT @update_notifications = SUM (p.execution_mode & 2), @update_ddl_trigger = SUM (p.execution_mode & 1)
FROM inserted i
JOIN dbo.syspolicy_target_sets s ON (i.target_set_id = s.target_set_id)
JOIN msdb.dbo.syspolicy_object_sets_internal os ON (s.object_set_id = os.object_set_id)
JOIN msdb.dbo.syspolicy_policies p ON (os.object_set_id = p.object_set_id)
WHERE 1 = dbo.syspolicy_fn_filter_complete (i.target_set_id) AND
((p.execution_mode & 3) > 0 AND p.is_enabled = 1 AND 1 = dbo.syspolicy_fn_eventing_filter (i.target_set_id))
IF (@update_ddl_trigger > 0)
EXEC sys.sp_syspolicy_update_ddl_trigger
IF (@update_notifications > 0)
EXEC sys.sp_syspolicy_update_event_notification
END
GO
PRINT 'Creating trigger [dbo].[syspolicy_update_target_set_level_trigger] on [dbo].[syspolicy_target_set_levels_internal]'
GO
CREATE TRIGGER [dbo].[syspolicy_update_target_set_level_trigger] ON [dbo].[syspolicy_target_set_levels_internal]
FOR UPDATE
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
DECLARE @update_notifications INT
DECLARE @update_ddl_trigger INT
SET @update_notifications = 0
SET @update_ddl_trigger = 0
IF UPDATE(condition_id)
BEGIN
DECLARE @level sysname
SET @level = NULL
-- Don't allow setting non-db levels for runtime policies
SELECT TOP 1 @level = i.level_name
FROM inserted i
JOIN dbo.syspolicy_target_sets s ON (i.target_set_id = s.target_set_id)
JOIN msdb.dbo.syspolicy_object_sets os ON s.object_set_id = os.object_set_id
JOIN msdb.dbo.syspolicy_policies p ON (os.object_set_id = p.object_set_id)
WHERE 1 = dbo.syspolicy_fn_filter_complete (i.target_set_id) AND
((p.execution_mode & 3) > 0 AND 0 = dbo.syspolicy_fn_eventing_filter (i.target_set_id))
IF @level IS NOT NULL
BEGIN
RAISERROR(34016, -1, -1, @level)
ROLLBACK TRANSACTION
END
END
SELECT @update_notifications = SUM (p.execution_mode & 2), @update_ddl_trigger = SUM (p.execution_mode & 1)
FROM inserted i
JOIN dbo.syspolicy_target_sets s ON (i.target_set_id = s.target_set_id)
JOIN msdb.dbo.syspolicy_object_sets os ON s.object_set_id = os.object_set_id
JOIN msdb.dbo.syspolicy_policies p ON (os.object_set_id = p.object_set_id)
WHERE 1 = dbo.syspolicy_fn_filter_complete (i.target_set_id) AND
((p.execution_mode & 3) > 0 AND p.is_enabled = 1 AND 1 = dbo.syspolicy_fn_eventing_filter (i.target_set_id))
IF (@update_ddl_trigger > 0)
EXEC sys.sp_syspolicy_update_ddl_trigger
IF (@update_notifications > 0)
EXEC sys.sp_syspolicy_update_event_notification
END
GO
PRINT 'Creating trigger [dbo].[syspolicy_insert_target_set_trigger] on [dbo].[syspolicy_target_sets_internal]'
GO
CREATE TRIGGER [dbo].[syspolicy_insert_target_set_trigger]
ON [dbo].[syspolicy_target_sets_internal]
FOR INSERT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
DECLARE @update_notifications INT
DECLARE @update_ddl_trigger INT
SET @update_notifications = 0
SET @update_ddl_trigger = 0
-- Only need to check Server TargetSets, as they don't have levels
SELECT @update_notifications = SUM (p.execution_mode & 2), @update_ddl_trigger = SUM (p.execution_mode & 1)
FROM inserted i
JOIN msdb.dbo.syspolicy_object_sets_internal os ON i.object_set_id = os.object_set_id
JOIN msdb.dbo.syspolicy_policies p ON (os.object_set_id = p.object_set_id)
WHERE i.type = 'SERVER' AND ((p.execution_mode & 3) > 0 AND p.is_enabled = 1)
IF (@update_ddl_trigger > 0)
EXEC sys.sp_syspolicy_update_ddl_trigger
IF (@update_notifications > 0)
EXEC sys.sp_syspolicy_update_event_notification
END
GO
PRINT 'Creating trigger [dbo].[syspolicy_delete_target_set_trigger] on [dbo].[syspolicy_target_sets_internal]'
GO
CREATE TRIGGER [dbo].[syspolicy_delete_target_set_trigger] ON [dbo].[syspolicy_target_sets_internal]
FOR DELETE
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
DECLARE @update_notifications INT
DECLARE @update_ddl_trigger INT
SET @update_notifications = 0
SET @update_ddl_trigger = 0
-- If this is cascade delete, there will be no policies to join
SELECT @update_notifications = SUM (p.execution_mode & 2), @update_ddl_trigger = SUM (p.execution_mode & 1)
FROM deleted d
JOIN msdb.dbo.syspolicy_object_sets_internal os ON d.object_set_id = os.object_set_id
JOIN msdb.dbo.syspolicy_policies p ON (os.object_set_id = p.object_set_id)
WHERE ((p.execution_mode & 3) > 0 AND p.is_enabled = 1)
IF (@update_ddl_trigger > 0)
EXEC sys.sp_syspolicy_update_ddl_trigger
IF (@update_notifications > 0)
EXEC sys.sp_syspolicy_update_event_notification
END
GO
---------------------------------------------------------------
-- Policy category subscription object
---------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_policy_category_subscriptions_internal')
BEGIN
PRINT 'Creating table [dbo].[syspolicy_policy_category_subscriptions_internal]...';
CREATE TABLE [dbo].[syspolicy_policy_category_subscriptions_internal] (
policy_category_subscription_id int IDENTITY(1,1),
target_type sysname NOT NULL,
target_object sysname NOT NULL,
policy_category_id int NOT NULL,
CONSTRAINT [PK_syspolicy_policy_category_subscriptions] PRIMARY KEY CLUSTERED (policy_category_subscription_id ASC)
);
CREATE UNIQUE INDEX [UX_syspolicy_policy_category_subscriptions] ON [dbo].[syspolicy_policy_category_subscriptions_internal](policy_category_id, target_object, target_type)
ALTER TABLE [dbo].[syspolicy_policy_category_subscriptions_internal]
ADD CONSTRAINT [FK_syspolicy_policy_category_subscriptions_syspolicy_policy_categories] FOREIGN KEY(policy_category_id)
REFERENCES [dbo].[syspolicy_policy_categories_internal] (policy_category_id)
ON DELETE CASCADE;
END
GO
PRINT 'Creating view [dbo].[syspolicy_policy_category_subscriptions]...'
GO
CREATE VIEW [dbo].[syspolicy_policy_category_subscriptions]
AS
SELECT
policy_category_subscription_id,
target_type,
target_object,
policy_category_id
FROM [dbo].[syspolicy_policy_category_subscriptions_internal]
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_add_policy_category_subscription]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_policy_category_subscription]
@target_type sysname,
@target_object sysname,
@policy_category sysname,
@policy_category_subscription_id int = NULL OUTPUT
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @retval int
IF(@target_type IS NOT NULL)
BEGIN
IF(@target_type <> 'DATABASE')
BEGIN
RAISERROR(34018,-1,-1,@target_type);
RETURN(1)
END
END
IF(NOT EXISTS(SELECT * FROM sys.databases WHERE name=@target_object))
BEGIN
RAISERROR(34019,-1,-1,@target_object);
RETURN(1)
END
-- convert category_name into id if needed
DECLARE @policy_category_id INT
BEGIN TRANSACTION
IF ( (@policy_category IS NOT NULL AND @policy_category != '') )
BEGIN
IF NOT EXISTS (SELECT * from syspolicy_policy_categories WHERE name = @policy_category)
BEGIN
INSERT INTO syspolicy_policy_categories_internal(name) VALUES (@policy_category)
SELECT @policy_category_id = SCOPE_IDENTITY()
END
ELSE
SELECT @policy_category_id = policy_category_id FROM syspolicy_policy_categories WHERE name = @policy_category
END
INSERT INTO msdb.[dbo].[syspolicy_policy_category_subscriptions_internal]
(target_type,
target_object,
policy_category_id)
VALUES
(@target_type,
@target_object,
@policy_category_id)
SELECT @retval = @@error
SET @policy_category_subscription_id = SCOPE_IDENTITY()
COMMIT TRANSACTION
RETURN(@retval)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_update_policy_category_subscription]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_policy_category_subscription]
@policy_category_subscription_id int,
@target_type sysname = NULL,
@target_object sysname = NULL,
@policy_category sysname = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
-- Turn [nullable] empty string parameters into NULLs
IF @target_type = '' SELECT @target_type = NULL
IF @target_object = '' SELECT @target_object = NULL
IF @policy_category = '' SELECT @policy_category = NULL
IF(@target_type IS NOT NULL)
BEGIN
IF(LOWER(@target_type) <> 'database')
BEGIN
RAISERROR(34018,-1,-1,@target_type);
RETURN(1)
END
END
IF(@target_object IS NOT NULL AND NOT EXISTS(SELECT * FROM sys.databases WHERE name=@target_object))
BEGIN
RAISERROR(34019,-1,-1,@target_object);
RETURN(1)
END
DECLARE @policy_category_id INT
SET @policy_category_id = NULL
BEGIN TRANSACTION
DECLARE @old_policy_category_id INT
SET @old_policy_category_id = NULL
IF ( (@policy_category IS NOT NULL) )
BEGIN
IF NOT EXISTS (SELECT * from syspolicy_policy_categories WHERE name = @policy_category)
BEGIN
-- add a new policy category
INSERT INTO syspolicy_policy_categories_internal(name) VALUES (@policy_category)
SELECT @policy_category_id = SCOPE_IDENTITY()
SELECT @old_policy_category_id = policy_category_id
FROM syspolicy_policy_category_subscriptions
WHERE policy_category_subscription_id = @policy_category_subscription_id
END
ELSE
SELECT @policy_category_id = policy_category_id FROM syspolicy_policy_categories WHERE name = @policy_category
END
DECLARE @group_usage_count INT
SELECT @group_usage_count = COUNT(*)
FROM syspolicy_policy_category_subscriptions
WHERE policy_category_id = @old_policy_category_id
SELECT @group_usage_count = @group_usage_count + COUNT(*)
FROM syspolicy_policies
WHERE policy_category_id = @old_policy_category_id
UPDATE msdb.[dbo].[syspolicy_policy_category_subscriptions_internal]
SET
target_type = ISNULL(@target_type, target_type),
target_object = ISNULL(@target_object, target_object),
policy_category_id = ISNULL(@policy_category_id, policy_category_id)
WHERE policy_category_subscription_id = @policy_category_subscription_id
IF (@@ROWCOUNT = 0)
BEGIN
DECLARE @policy_category_subscription_id_as_char VARCHAR(36)
SELECT @policy_category_subscription_id_as_char = CONVERT(VARCHAR(36), @policy_category_subscription_id)
RAISERROR(14262, -1, -1, '@policy_category_subscription_id', @policy_category_subscription_id_as_char)
ROLLBACK TRANSACTION
RETURN(1) -- Failure
END
-- delete the old entry if it was used only by this policy
DELETE syspolicy_policy_categories_internal WHERE
policy_category_id = @old_policy_category_id
AND 1 = @group_usage_count
COMMIT TRANSACTION
RETURN (0)
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_policy_category_subscription]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_policy_category_subscription]
@policy_category_subscription_id int
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @old_policy_category_id INT
SELECT @old_policy_category_id = policy_category_id
FROM dbo.syspolicy_policy_category_subscriptions
WHERE policy_category_subscription_id = @policy_category_subscription_id
DECLARE @group_usage_count INT
SELECT @group_usage_count = COUNT(name)
FROM syspolicy_policies pd
WHERE pd.policy_category_id = @old_policy_category_id
DECLARE @subscription_group_usage_count INT
SELECT @subscription_group_usage_count = COUNT(*)
FROM syspolicy_policy_category_subscriptions
WHERE policy_category_id = @old_policy_category_id
SELECT @group_usage_count = @group_usage_count + @subscription_group_usage_count
DELETE msdb.dbo.syspolicy_policy_category_subscriptions_internal
WHERE policy_category_subscription_id = @policy_category_subscription_id
IF (@@ROWCOUNT = 0)
BEGIN
DECLARE @policy_category_subscription_id_as_char VARCHAR(36)
SELECT @policy_category_subscription_id_as_char = CONVERT(VARCHAR(36), @policy_category_subscription_id)
RAISERROR(14262, -1, -1, '@policy_category_subscription_id', @policy_category_subscription_id_as_char)
RETURN(1) -- Failure
END
RETURN (0)
END
GO
GO
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_system_health_state_internal')
BEGIN
PRINT 'Creating table [dbo].[syspolicy_system_health_state_internal]...'
CREATE TABLE [dbo].[syspolicy_system_health_state_internal](
health_state_id bigint IDENTITY PRIMARY KEY CLUSTERED,
policy_id int NOT NULL REFERENCES [dbo].[syspolicy_policies_internal],
last_run_date datetime NOT NULL,
target_query_expression_with_id nvarchar(400) NOT NULL,
target_query_expression nvarchar(max) NOT NULL,
result bit NOT NULL);
CREATE INDEX IX_syspolicy_system_health_state_internal_policy_id ON
[dbo].[syspolicy_system_health_state_internal](policy_id);
CREATE INDEX IX_syspolicy_system_health_state_internal_target_query_expression_with_id ON
[dbo].[syspolicy_system_health_state_internal](target_query_expression_with_id);
END
GO
CREATE VIEW [dbo].[syspolicy_system_health_state]
AS
SELECT
health_state_id,
policy_id,
last_run_date,
target_query_expression_with_id,
target_query_expression,
result
FROM [dbo].[syspolicy_system_health_state_internal]
GO
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_policy_execution_history_internal')
BEGIN
PRINT 'Creating table [dbo].[syspolicy_policy_execution_history_internal]...';
CREATE TABLE syspolicy_policy_execution_history_internal (
history_id bigint IDENTITY PRIMARY KEY CLUSTERED,
policy_id int NOT NULL REFERENCES syspolicy_policies_internal,
start_date datetime NOT NULL DEFAULT (GETDATE()),
end_date datetime NULL,
result bit NOT NULL DEFAULT (0),
is_full_run bit NOT NULL DEFAULT (1),
exception_message nvarchar(max) NULL,
exception nvarchar(max) NULL
);
CREATE INDEX IX_syspolicy_policy_execution_history_internal_end_date_policy_id
ON [dbo].[syspolicy_policy_execution_history_internal](policy_id, end_date);
CREATE INDEX IX_syspolicy_policy_execution_history_internal_policy_id
ON [dbo].[syspolicy_policy_execution_history_internal](policy_id);
END
PRINT 'Creating trigger [syspolicy_update_system_health_state]...'
GO
CREATE TRIGGER [syspolicy_update_system_health_state] ON [dbo].[syspolicy_policy_execution_history_internal]
AFTER UPDATE
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
-- if the entire policy has been checked delete all entries
-- regarding that policy
DELETE FROM [dbo].[syspolicy_system_health_state_internal]
WHERE policy_id in (SELECT policy_id FROM inserted WHERE is_full_run = 1)
-- Note: in the queries below new records are added only for
-- policies that are enabled for automation
-- if the policy is evaluated against a single target
-- delete the old entry
DELETE FROM [dbo].[syspolicy_system_health_state_internal]
WHERE policy_id in
(SELECT i.policy_id FROM inserted i WHERE i.is_full_run = 0) AND
target_query_expression_with_id in (SELECT target_query_expression_with_id
FROM [dbo].[syspolicy_policy_execution_history_details_internal] d
INNER JOIN inserted i2 ON i2.history_id = d.history_id
WHERE i2.is_full_run = 0)
-- insert the detail rows, but only for failures
-- this is done both for the full runs and for the partial runs
-- we will not insert anything if this is a ghost record, i.e.
-- target_query_expression_with_id is null
-- this will happen when we log prevent policies
INSERT INTO [dbo].[syspolicy_system_health_state_internal]
(policy_id, last_run_date, target_query_expression_with_id, target_query_expression, result)
SELECT i.policy_id, d.execution_date, d.target_query_expression_with_id, d.target_query_expression, d.result
FROM inserted i
INNER JOIN [dbo].[syspolicy_policy_execution_history_details_internal] d on i.history_id = d.history_id
INNER JOIN [dbo].[syspolicy_policies] p on i.policy_id = p.policy_id
WHERE d.result = 0 AND p.is_enabled = 1 AND d.target_query_expression_with_id != N''
-- delete all the success detail rows with no expression
-- these are rows inserted so that we can update the system health state
-- make an exception if the global switch says we should keep those records
IF( 0 = (SELECT ISNULL(convert(bit, current_value), 0) FROM msdb.dbo.syspolicy_configuration WHERE name = 'LogOnSuccess'))
BEGIN
DELETE FROM d
FROM [dbo].[syspolicy_policy_execution_history_details_internal] d
INNER JOIN inserted i ON i.history_id = d.history_id
WHERE d.result_detail = N''
END
END
GO
CREATE VIEW [dbo].[syspolicy_policy_execution_history]
AS
SELECT
history_id,
policy_id,
start_date,
end_date,
result,
exception_message,
exception
FROM [dbo].[syspolicy_policy_execution_history_internal]
GO
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_policy_execution_history_details_internal')
BEGIN
PRINT 'Creating table [dbo].[syspolicy_policy_execution_history_details_internal]...';
CREATE TABLE syspolicy_policy_execution_history_details_internal
(
detail_id bigint IDENTITY,
history_id bigint NOT NULL REFERENCES syspolicy_policy_execution_history_internal ON DELETE CASCADE,
target_query_expression nvarchar(4000) NOT NULL,
target_query_expression_with_id nvarchar(4000) NOT NULL,
execution_date datetime NOT NULL DEFAULT (GETDATE()),
result bit NOT NULL,
result_detail nvarchar(max) NULL,
exception_message nvarchar(max) NULL,
exception nvarchar(max) NULL,
CONSTRAINT [PK_syspolicy_policy_execution_history_details_id] PRIMARY KEY CLUSTERED(history_id, detail_id)
)
END
GO
CREATE VIEW [dbo].[syspolicy_policy_execution_history_details]
AS
SELECT
detail_id,
history_id,
target_query_expression,
execution_date,
result,
result_detail,
exception_message,
exception
FROM [dbo].[syspolicy_policy_execution_history_details_internal]
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_log_policy_execution_start]...'
GO
CREATE PROC [dbo].[sp_syspolicy_log_policy_execution_start]
@policy_id int,
@is_full_run bit,
@history_id bigint OUTPUT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole', 0
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @ret int
SET @history_id = 0
EXEC @ret = dbo.sp_syspolicy_verify_policy_identifiers NULL, @policy_id
IF @ret <> 0 RETURN -1
INSERT syspolicy_policy_execution_history_internal (policy_id, is_full_run) VALUES (@policy_id, @is_full_run)
SET @history_id = SCOPE_IDENTITY ()
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_log_policy_execution_end]...'
GO
CREATE PROC [dbo].[sp_syspolicy_log_policy_execution_end]
@history_id bigint,
@result bit,
@exception_message nvarchar(max) = NULL,
@exception nvarchar(max) = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole', 0
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
UPDATE syspolicy_policy_execution_history_internal
SET result = @result,
end_date = GETDATE(),
exception_message = @exception_message,
exception = @exception
WHERE history_id = @history_id
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_log_policy_execution_detail]...'
GO
CREATE PROC [dbo].[sp_syspolicy_log_policy_execution_detail]
@history_id bigint,
@target_query_expression nvarchar(4000),
@target_query_expression_with_id nvarchar(4000),
@result bit,
@result_detail nvarchar(max),
@exception_message nvarchar(max) = NULL,
@exception nvarchar(max) = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole', 0
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
BEGIN TRANSACTION
DECLARE @is_valid_entry INT
-- take an update lock on this table first to prevent deadlock
SELECT @is_valid_entry = count(*) FROM syspolicy_policy_execution_history_internal
WITH (UPDLOCK)
WHERE history_id = @history_id
INSERT syspolicy_policy_execution_history_details_internal (
history_id,
target_query_expression,
target_query_expression_with_id,
result,
result_detail,
exception_message,
exception)
VALUES (
@history_id,
@target_query_expression,
@target_query_expression_with_id,
@result,
@result_detail,
@exception_message,
@exception)
IF( @@TRANCOUNT > 0)
COMMIT
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_policy_execution_history]...'
GO
CREATE PROC [dbo].[sp_syspolicy_delete_policy_execution_history]
@policy_id int,
@oldest_date datetime
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
IF @oldest_date IS NULL
BEGIN
IF (@policy_id IS NULL)
DELETE syspolicy_policy_execution_history_internal
ELSE
DELETE syspolicy_policy_execution_history_internal WHERE policy_id = @policy_id
END
ELSE
BEGIN
IF (@policy_id IS NULL)
DELETE syspolicy_policy_execution_history_internal WHERE start_date < @oldest_date
ELSE
DELETE syspolicy_policy_execution_history_internal WHERE policy_id = @policy_id AND start_date < @oldest_date
END
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_mark_system]...'
GO
CREATE PROC dbo.sp_syspolicy_mark_system @type sysname, @name sysname=NULL, @object_id int=NULL, @marker bit=NULL
AS
BEGIN
-- If @marker IS NULL simple return the state
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @retval int
IF (UPPER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'POLICY')
BEGIN
EXEC @retval = sp_syspolicy_verify_policy_identifiers @name, @object_id OUTPUT
IF (@retval <> 0)
RETURN (1)
IF @marker IS NULL
BEGIN
SELECT policy_id, name, is_system FROM syspolicy_policies_internal WHERE policy_id = @object_id
END
ELSE
BEGIN
UPDATE msdb.dbo.syspolicy_policies_internal
SET is_system = @marker
WHERE policy_id = @object_id
END
END
ELSE IF (UPPER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'CONDITION')
BEGIN
EXEC @retval = sp_syspolicy_verify_condition_identifiers @name, @object_id OUTPUT
IF (@retval <> 0)
RETURN (1)
IF @marker IS NULL
BEGIN
SELECT condition_id, name, is_system FROM syspolicy_conditions_internal WHERE condition_id = @object_id
END
ELSE
BEGIN
UPDATE msdb.dbo.syspolicy_conditions_internal
SET is_system = @marker
WHERE condition_id = @object_id
END
END
ELSE IF (UPPER(@type collate SQL_Latin1_General_CP1_CS_AS) = N'OBJECTSET')
BEGIN
EXEC @retval = sp_syspolicy_verify_object_set_identifiers @name, @object_id OUTPUT
IF (@retval <> 0)
RETURN (1)
IF @marker IS NULL
BEGIN
SELECT object_set_id, object_set_name, is_system FROM syspolicy_object_sets_internal WHERE object_set_id = @object_id
END
ELSE
BEGIN
UPDATE msdb.dbo.syspolicy_object_sets_internal
SET is_system = @marker
WHERE object_set_id = @object_id
END
END
ELSE
BEGIN
RAISERROR(14262, -1, -1, '@type', @type)
RETURN(1) -- Failure
END
SELECT @retval = @@error
RETURN(@retval)
END
GO
-----------------------------------------------------------
-- event processing
-----------------------------------------------------------
PRINT 'Creating function [dbo].[syspolicy_fn_get_type_name]...'
GO
CREATE FUNCTION [dbo].[syspolicy_fn_get_type_name](@event_type_name sysname)
RETURNS sysname
AS
BEGIN
RETURN
(CASE LOWER(@event_type_name)
WHEN 'procedure' THEN 'StoredProcedure'
WHEN 'function' THEN 'UserDefinedFunction'
WHEN 'type' THEN 'UserDefinedType'
WHEN 'sql user' THEN 'User'
WHEN 'certificate user' THEN 'User'
WHEN 'asymmetric key user' THEN 'User'
WHEN 'windows user' THEN 'User'
WHEN 'group user' THEN 'User'
WHEN 'application role' THEN 'ApplicationRole'
ELSE UPPER(SUBSTRING(@event_type_name, 1,1)) + LOWER(SUBSTRING(@event_type_name, 2,LEN(@event_type_name)))
END)
END
GO
IF OBJECT_ID ('[dbo].[syspolicy_execution_internal]') IS NULL
BEGIN
PRINT 'Creating table [dbo].[syspolicy_execution_internal]...'
CREATE TABLE [dbo].[syspolicy_execution_internal] (
policy_id int,
synchronous bit,
event_data xml)
END
GO
IF OBJECT_ID ('[dbo].[syspolicy_execution_trigger]') IS NOT NULL
BEGIN
DROP TRIGGER [dbo].[syspolicy_execution_trigger]
END
GO
CREATE TRIGGER [dbo].[syspolicy_execution_trigger] ON [dbo].[syspolicy_execution_internal]
INSTEAD OF INSERT
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN;
END
IF NOT EXISTS (SELECT * FROM inserted)
RETURN
DECLARE @policy_id int
DECLARE @synchronous bit
DECLARE @event_data xml
DECLARE affected_policies CURSOR LOCAL FOR
SELECT policy_id, synchronous, event_data FROM inserted
OPEN affected_policies
FETCH NEXT FROM affected_policies INTO @policy_id, @synchronous, @event_data
DECLARE @err int
SET @err = 0
WHILE (@@FETCH_STATUS = 0 AND (@synchronous = 0 OR @err = 0))
BEGIN
DECLARE @pol_name sysname
SELECT @pol_name = p.name
FROM dbo.syspolicy_policies p
WHERE p.policy_id = @policy_id
IF (@synchronous = 0)
BEGIN
-- trace what policy is processing this event
DECLARE @msg nvarchar(1000)
SET @msg = N'Policy ''' + @pol_name + ''' was activated by an event.'
RAISERROR(@msg, 1, 1) with log
END
-- execute the policy
EXEC @err = msdb.sys.sp_syspolicy_execute_policy @policy_name =@pol_name, @event_data = @event_data, @synchronous = @synchronous
-- move to the next policy if we're checking the policy
-- or if we are in enforce mode and we haven't failed
IF( @synchronous = 0 OR @err = 0)
FETCH NEXT FROM affected_policies INTO @policy_id, @synchronous, @event_data
END
CLOSE affected_policies
DEALLOCATE affected_policies
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_dispatch_event]...'
GO
-- These settings are necessary to read XML.
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET NUMERIC_ROUNDABORT OFF
SET QUOTED_IDENTIFIER ON
GO
-- procedure that processes an event and decides
-- what binding should handle it
CREATE PROCEDURE [dbo].[sp_syspolicy_dispatch_event] @event_data xml, @synchronous bit
AS
BEGIN
-- disable these as the caller may not have SHOWPLAN permission
SET STATISTICS XML OFF
SET STATISTICS PROFILE OFF
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
IF ( @synchronous = 0)
PRINT CONVERT(nvarchar(max), @event_data)
DECLARE @event_type sysname
DECLARE @object_type sysname
DECLARE @database sysname
DECLARE @mode int
DECLARE @filter_expression nvarchar(4000)
DECLARE @filter_expression_skeleton nvarchar(4000)
SET @mode = (case @synchronous when 1 then 1 else 2 end)
-- These settings are necessary to read XML.
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET NUMERIC_ROUNDABORT OFF
SET QUOTED_IDENTIFIER ON
SET NOCOUNT ON
SELECT
@event_type = T.c.value('(EventType/text())[1]', 'sysname')
, @database = T.c.value('(DatabaseName/text())[1]', 'sysname')
, @object_type = T.c.value('(ObjectType/text())[1]', 'sysname')
FROM @event_data.nodes('/EVENT_INSTANCE') T(c)
-- we are going to ignore events that affect subobjects
IF (@event_type = N'ALTER_DATABASE' AND
1 = @event_data.exist('EVENT_INSTANCE/AlterDatabaseActionList')) OR
(@event_type = N'ALTER_TABLE' AND
1 = @event_data.exist('EVENT_INSTANCE/AlterTableActionList'))
BEGIN
RETURN;
END
-- convert trace numerical objecttypes to string
IF (ISNUMERIC(@object_type) = 1)
select @object_type = name from master.dbo.spt_values where type = 'EOB' and number = @object_type
-- these events do not have ObjectType and ObjectName
IF ((@object_type IS NULL) AND @event_type IN ('CREATE_DATABASE', 'DROP_DATABASE', 'ALTER_DATABASE'))
BEGIN
SET @object_type = 'DATABASE'
END
INSERT msdb.dbo.syspolicy_execution_internal
SELECT p.policy_id , @synchronous, @event_data
FROM dbo.syspolicy_policies p -- give me all the policies
INNER JOIN dbo.syspolicy_conditions_internal c ON c.condition_id = p.condition_id -- and their conditions
INNER JOIN dbo.syspolicy_facet_events fe ON c.facet_id = fe.management_facet_id -- and the facet events that are affected by the condition
INNER JOIN dbo.syspolicy_target_sets ts ON ts.object_set_id = p.object_set_id AND ts.type = fe.target_type -- and the target sets in the object set of the policy, with event types that are affected by the condition
LEFT JOIN dbo.syspolicy_policy_category_subscriptions pgs ON pgs.policy_category_id = p.policy_category_id -- and the policy category subscriptions, if any
LEFT JOIN dbo.syspolicy_target_set_levels tsl ON tsl.target_set_id = ts.target_set_id AND tsl.level_name = 'Database' -- and the database target set levels associated with any of the target sets, if any
LEFT JOIN dbo.syspolicy_conditions_internal lc ON lc.condition_id = tsl.condition_id -- and any conditions on the target set level, if any
LEFT JOIN dbo.syspolicy_policy_categories cat ON p.policy_category_id = cat.policy_category_id -- and the policy categories, if any
WHERE fe.event_name=@event_type AND -- event type matches the fired event
p.is_enabled = 1 AND -- policy is enabled
fe.target_type_alias = @object_type AND -- target type matches the object in the event
ts.enabled = 1 AND -- target set is enabled
-- 1 means Enforce, 2 means CheckOnChange
(p.execution_mode & @mode) = @mode AND -- policy mode matches the requested mode
((p.policy_category_id IS NULL) OR (cat.mandate_database_subscriptions = 1) OR ( ts.type_skeleton NOT LIKE 'Server/Database%') OR (@database IS NOT NULL AND pgs.target_object = @database)) AND
((@database IS NULL) OR
(@database IS NOT NULL AND
(tsl.condition_id IS NULL OR
(tsl.condition_id IS NOT NULL AND
((lc.is_name_condition=1 AND @database = lc.obj_name) OR
(lc.is_name_condition=2 AND @database LIKE lc.obj_name) OR
(lc.is_name_condition=3 AND @database != lc.obj_name) OR
(lc.is_name_condition=4 AND @database NOT LIKE lc.obj_name))
)
)
)
)
-- NOTE: if we haven't subscribed via an Endpoint facet on those events
-- we know for sure they will not be processed by the ServerAreaFacet policies
-- because syspolicy_facet_events expects @target_type to be SERVER
-- so the filter will leave them out, and we are going to generate a fake
-- event to make those policies run
IF( @synchronous = 0 AND
(@event_type IN ('ALTER_ENDPOINT', 'CREATE_ENDPOINT', 'DROP_ENDPOINT')))
BEGIN
DECLARE @fake_event_data xml
SET @fake_event_data = CONVERT(xml, '<EVENT_INSTANCE><EventType>SAC_ENDPOINT_CHANGE</EventType><ObjectType>21075</ObjectType><ObjectName/><DatabaseName>master</DatabaseName></EVENT_INSTANCE>')
EXEC [dbo].[sp_syspolicy_dispatch_event] @event_data = @fake_event_data, @synchronous = 0
END
END
GO
/*
* Asynchronous events collection via event notifications
*/
PRINT N'Dropping service [syspolicy_event_listener]...'
GO
IF EXISTS (SELECT * FROM sys.services WHERE name = N'syspolicy_event_listener')
DROP SERVICE [syspolicy_event_listener]
GO
PRINT N'Dropping queue [syspolicy_event_queue]...'
GO
IF EXISTS (SELECT * FROM sys.service_queues WHERE name = N'syspolicy_event_queue')
DROP QUEUE [syspolicy_event_queue]
GO
PRINT N'Creating queue [syspolicy_event_queue]...'
GO
CREATE QUEUE [syspolicy_event_queue]
GO
PRINT N'Creating service [syspolicy_event_listener]...'
GO
CREATE SERVICE [syspolicy_event_listener]
ON QUEUE [syspolicy_event_queue]
([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification]);
GO
IF EXISTS (SELECT * FROM sys.procedures WHERE name = N'sp_syspolicy_events_reader')
DROP PROCEDURE [sp_syspolicy_events_reader]
GO
PRINT N'Creating procedure [sp_syspolicy_events_reader]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_events_reader]
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @dh uniqueidentifier;
DECLARE @mt sysname;
DECLARE @body varbinary(max);
DECLARE @msg nvarchar(max)
BEGIN TRANSACTION;
WAITFOR (RECEIVE TOP (1)
@dh = conversation_handle,
@mt = message_type_name,
@body = message_body
FROM [syspolicy_event_queue]), timeout 5000;
WHILE (@dh is not null)
BEGIN
IF (@mt = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error')
BEGIN
-- @body contains the error
DECLARE @bodyStr nvarchar(max)
SET @bodyStr = convert(nvarchar(max), @body)
RAISERROR (34001, 1,1, @bodyStr) with log;
END CONVERSATION @dh;
END
IF (@mt = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog')
BEGIN
RAISERROR (34002, 1,1) with log;
END CONVERSATION @dh;
END
IF (@mt = N'http://schemas.microsoft.com/SQL/Notifications/EventNotification')
BEGIN
-- process the event
BEGIN TRY
EXEC [dbo].[sp_syspolicy_dispatch_event] @event_data = @body, @synchronous = 0
END TRY
BEGIN CATCH
-- report the error
DECLARE @errorNumber int
DECLARE @errorMessage nvarchar(max)
SET @errorNumber = ERROR_NUMBER()
SET @errorMessage = ERROR_MESSAGE()
RAISERROR (34003, 1,1, @errorNumber, @errorMessage ) with log;
END CATCH
END
-- every message is handled in its own transaction
COMMIT TRANSACTION;
SELECT @dh = null;
BEGIN TRANSACTION;
WAITFOR (RECEIVE TOP (1)
@dh = conversation_handle,
@mt = message_type_name,
@body = message_body
FROM [syspolicy_event_queue]), TIMEOUT 5000;
END
COMMIT;
END
GO
IF OBJECT_ID('[dbo].[syspolicy_configuration_internal]') IS NULL
BEGIN
PRINT 'Creating table [dbo].[syspolicy_configuration_internal]...'
CREATE TABLE [dbo].[syspolicy_configuration_internal] (
name sysname PRIMARY KEY CLUSTERED NOT NULL,
current_value sql_variant NOT NULL);
INSERT INTO [dbo].[syspolicy_configuration_internal] (name, current_value)
VALUES (N'Enabled', 1);
INSERT INTO [dbo].[syspolicy_configuration_internal] (name, current_value)
VALUES (N'HistoryRetentionInDays', 0);
INSERT INTO [dbo].[syspolicy_configuration_internal] (name, current_value)
VALUES (N'LogOnSuccess', 0);
END
GO
PRINT 'Creating view [dbo].[syspolicy_configuration] ...'
GO
CREATE VIEW [dbo].[syspolicy_configuration]
AS
SELECT
name,
CASE WHEN name = N'Enabled' and SERVERPROPERTY('EngineEdition') = 4 THEN 0 ELSE current_value END AS current_value
FROM [dbo].[syspolicy_configuration_internal]
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_set_config_history_retention] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_set_config_history_retention]
@value sql_variant
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
UPDATE [msdb].[dbo].[syspolicy_configuration_internal]
SET current_value = @value
WHERE name = N'HistoryRetentionInDays';
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_set_log_on_success] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_set_log_on_success]
@value sql_variant
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
UPDATE [msdb].[dbo].[syspolicy_configuration_internal]
SET current_value = @value
WHERE name = N'LogOnSuccess';
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_set_config_enabled] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_set_config_enabled]
@value sql_variant
AS
BEGIN
DECLARE @retval_check int;
SET NOCOUNT ON
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @val bit;
SET @val = CONVERT(bit, @value);
IF (@val = 1)
BEGIN
DECLARE @engine_edition INT
SELECT @engine_edition = CAST(SERVERPROPERTY('EngineEdition') AS INT)
IF @engine_edition = 4 -- All SQL Express types + embedded
BEGIN
RAISERROR (34054, 16, 1)
RETURN 34054
END
UPDATE [msdb].[dbo].[syspolicy_configuration_internal]
SET current_value = @value
WHERE name = N'Enabled';
-- enable policy automation
ALTER QUEUE [syspolicy_event_queue] WITH ACTIVATION (STATUS = ON)
EXEC sys.sp_syspolicy_update_ddl_trigger;
EXEC sys.sp_syspolicy_update_event_notification;
END
ELSE
BEGIN
UPDATE [msdb].[dbo].[syspolicy_configuration_internal]
SET current_value = @value
WHERE name = N'Enabled';
-- disable policy automation
ALTER QUEUE [syspolicy_event_queue] WITH ACTIVATION (STATUS = OFF)
IF EXISTS (SELECT * FROM sys.server_event_notifications WHERE name = N'syspolicy_event_notification')
DROP EVENT NOTIFICATION [syspolicy_event_notification] ON SERVER
IF EXISTS (SELECT * FROM sys.server_triggers WHERE name = N'syspolicy_server_trigger')
DISABLE TRIGGER [syspolicy_server_trigger] ON ALL SERVER
END
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_configure] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_configure]
@name sysname,
@value sql_variant
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
IF (0 != @retval_check)
BEGIN
RETURN @retval_check
END
DECLARE @value_type sysname;
IF (@name=N'Enabled')
BEGIN
SET @value_type = CONVERT(sysname, SQL_VARIANT_PROPERTY(@value, 'BaseType'));
IF (@value_type != 'int')
BEGIN
RAISERROR (34021, -1, -1, @name, @value_type);
RETURN 34021;
END
EXEC msdb.[dbo].[sp_syspolicy_set_config_enabled] @value;
END
ELSE
IF (@name = N'HistoryRetentionInDays')
BEGIN
SET @value_type = CONVERT(sysname, SQL_VARIANT_PROPERTY(@value, 'BaseType'));
IF (@value_type != 'int')
BEGIN
RAISERROR (34021, -1, -1, @name, @value_type);
RETURN 34021;
END
EXEC msdb.[dbo].[sp_syspolicy_set_config_history_retention] @value;
END
ELSE
IF (@name=N'LogOnSuccess')
BEGIN
SET @value_type = CONVERT(sysname, SQL_VARIANT_PROPERTY(@value, 'BaseType'));
IF (@value_type != 'int')
BEGIN
RAISERROR (34021, -1, -1, @name, @value_type);
RETURN 34021;
END
EXEC msdb.[dbo].[sp_syspolicy_set_log_on_success] @value;
END
ELSE
BEGIN
RAISERROR(34020, -1, -1, @name);
RETURN 34020;
END
RETURN 0;
END
GO
PRINT 'Creating function [dbo].[fn_syspolicy_is_automation_enabled] ...'
GO
CREATE FUNCTION fn_syspolicy_is_automation_enabled()
RETURNS bit
AS
BEGIN
DECLARE @ret bit;
SELECT @ret = CONVERT(bit, current_value)
FROM msdb.dbo.syspolicy_configuration
WHERE name = 'Enabled'
RETURN @ret;
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_repair_policy_automation] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_repair_policy_automation]
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole';
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check;
END
BEGIN TRANSACTION;
BEGIN TRY
SET NOCOUNT ON
DECLARE @policies_copy TABLE (
policy_id int ,
name sysname NOT NULL,
condition_id int NOT NULL,
root_condition_id int NULL,
execution_mode int NOT NULL,
policy_category_id int NULL,
schedule_uid uniqueidentifier NULL,
description nvarchar(max) NOT NULL ,
help_text nvarchar(4000) NOT NULL ,
help_link nvarchar(2083) NOT NULL ,
object_set_id INT NULL,
is_enabled bit NOT NULL,
is_system bit NOT NULL);
INSERT INTO @policies_copy
SELECT policy_id,
name,
condition_id,
root_condition_id,
execution_mode,
policy_category_id,
schedule_uid,
description,
help_text,
help_link,
object_set_id,
is_enabled,
is_system
FROM msdb.dbo.syspolicy_policies_internal;
DELETE FROM syspolicy_policies_internal;
SET IDENTITY_INSERT msdb.dbo.syspolicy_policies_internal ON
INSERT INTO msdb.dbo.syspolicy_policies_internal (
policy_id,
name,
condition_id,
root_condition_id,
execution_mode,
policy_category_id,
schedule_uid,
description,
help_text,
help_link,
object_set_id,
is_enabled,
is_system)
SELECT
policy_id,
name,
condition_id,
root_condition_id,
execution_mode,
policy_category_id,
schedule_uid,
description,
help_text,
help_link,
object_set_id,
is_enabled,
is_system
FROM @policies_copy;
SET IDENTITY_INSERT msdb.dbo.syspolicy_policies_internal OFF;
SET NOCOUNT OFF;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
RAISERROR (14351, -1, -1);
RETURN 1;
END CATCH
-- commit the transaction we started
COMMIT TRANSACTION;
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_purge_history] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_purge_history] @include_system bit=0
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole';
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check;
END
DECLARE @retention_interval_in_days_variant sql_variant
SET @retention_interval_in_days_variant = (SELECT current_value
FROM msdb.dbo.syspolicy_configuration
WHERE name = N'HistoryRetentionInDays');
DECLARE @retention_interval_in_days int;
SET @retention_interval_in_days = CONVERT(int, @retention_interval_in_days_variant);
IF( @retention_interval_in_days <= 0)
RETURN 0;
DECLARE @cutoff_date datetime;
SET @cutoff_date = DATEADD(day, -@retention_interval_in_days, GETDATE());
-- delete old policy history records
BEGIN TRANSACTION
DELETE d
FROM msdb.dbo.syspolicy_policy_execution_history_details_internal d
INNER JOIN msdb.dbo.syspolicy_policy_execution_history_internal h ON d.history_id = h.history_id
INNER JOIN msdb.dbo.syspolicy_policies p ON h.policy_id = p.policy_id
WHERE h.end_date < @cutoff_date AND (p.is_system = 0 OR p.is_system = @include_system)
DELETE h
FROM msdb.dbo.syspolicy_policy_execution_history_internal h
INNER JOIN msdb.dbo.syspolicy_policies p ON h.policy_id = p.policy_id
WHERE h.end_date < @cutoff_date AND (p.is_system = 0 OR p.is_system = @include_system)
COMMIT TRANSACTION
-- delete policy subscriptions that refer to the nonexistent databases
DELETE s
FROM msdb.dbo.syspolicy_policy_category_subscriptions_internal s
LEFT OUTER JOIN master.sys.databases d ON s.target_object = d.name
WHERE s.target_type = 'DATABASE' AND d.database_id IS NULL
RETURN 0;
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_create_purge_job] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_create_purge_job]
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole';
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check;
END
-- create a policy history retention maintenance job
-- first check if this job already exists
IF EXISTS (SELECT *
FROM msdb.dbo.syspolicy_configuration c
WHERE c.name = 'PurgeHistoryJobGuid')
BEGIN
RETURN;
END
BEGIN TRANSACTION;
DECLARE @ReturnCode INT;
SELECT @ReturnCode = 0;
DECLARE @job_name sysname;
-- create unique job name
SET @job_name = N'syspolicy_purge_history';
WHILE (EXISTS (SELECT * FROM msdb..sysjobs WHERE name = @job_name))
BEGIN
SET @job_name = N'syspolicy_purge_history_' + RIGHT(STR(FLOOR(RAND() * 100000000)),8);
END
DECLARE @sa_account_name sysname
SET @sa_account_name = SUSER_Name(0x1)
DECLARE @jobId BINARY(16);
EXEC @ReturnCode = msdb.dbo.sp_add_job
@job_name=@job_name,
@enabled=1,
@notify_level_eventlog=0,
@notify_level_email=0,
@notify_level_netsend=0,
@notify_level_page=0,
@delete_level=0,
@owner_login_name=@sa_account_name,
@job_id = @jobId OUTPUT;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep
@job_id=@jobId,
@step_name=N'Verify that automation is enabled.',
@step_id=1,
@cmdexec_success_code=0,
@on_success_action=3,
@on_success_step_id=0,
@on_fail_action=1,
@on_fail_step_id=0,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'TSQL',
@command=N'IF (msdb.dbo.fn_syspolicy_is_automation_enabled() != 1)
BEGIN
RAISERROR(34022, 16, 1)
END',
@database_name=N'master',
@flags=0;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep
@job_id=@jobId,
@step_name=N'Purge history.',
@step_id=2,
@cmdexec_success_code=0,
@on_success_action=3,
@on_success_step_id=0,
@on_fail_action=2,
@on_fail_step_id=0,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'TSQL',
@command=N'EXEC msdb.dbo.sp_syspolicy_purge_history',
@database_name=N'master',
@flags=0;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;
DECLARE @command nvarchar(1000);
SET @command = N'if (''$(ESCAPE_SQUOTE(INST))'' -eq ''MSSQLSERVER'') {$a = ''\DEFAULT''} ELSE {$a = ''''};
(Get-Item SQLSERVER:\SQLPolicy\$(ESCAPE_NONE(SRVR))$a).EraseSystemHealthPhantomRecords()'
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep
@job_id=@jobId,
@step_name=N'Erase Phantom System Health Records.',
@step_id=3,
@cmdexec_success_code=0,
@on_success_action=1,
@on_success_step_id=0,
@on_fail_action=2,
@on_fail_step_id=0,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'PowerShell',
@command=@command,
@database_name=N'master',
@flags=0;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = @@SERVERNAME;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;
-- run this job every day at 2AM
EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule
@job_id=@jobId,
@name=N'syspolicy_purge_history_schedule',
@enabled=1,
@freq_type=4,
@freq_interval=1,
@freq_subday_type=1,
@freq_subday_interval=0,
@freq_relative_interval=0,
@freq_recurrence_factor=0,
@active_start_date=20080101,
@active_end_date=99991231,
@active_start_time=20000,
@active_end_time=235959;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;
INSERT INTO [msdb].[dbo].[syspolicy_configuration_internal] (name, current_value)
VALUES (N'PurgeHistoryJobGuid', @jobId);
COMMIT TRANSACTION;
RETURN;
QuitWithRollback:
IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION;
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_purge_health_state] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_purge_health_state]
@target_tree_root_with_id nvarchar(400) = NULL
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole';
IF ( 0!= @retval_check)
BEGIN
RETURN @retval_check;
END
IF (@target_tree_root_with_id IS NULL)
BEGIN
DELETE FROM msdb.dbo.syspolicy_system_health_state_internal;
END
ELSE
BEGIN
DECLARE @target_mask nvarchar(801);
SET @target_mask = @target_tree_root_with_id;
-- we need to escape all the characters that can be part of the
-- LIKE pattern
SET @target_mask = REPLACE(@target_mask, '[', '\[');
SET @target_mask = REPLACE(@target_mask, ']', '\]');
SET @target_mask = REPLACE(@target_mask, '_', '\_');
SET @target_mask = REPLACE(@target_mask, '%', '\%');
SET @target_mask = @target_mask + '%';
DELETE FROM msdb.dbo.syspolicy_system_health_state_internal
WHERE target_query_expression_with_id LIKE @target_mask ESCAPE '\';
END
RETURN 0;
END
GO
-----------------------------------------------------------
-- Security for policy objects
-----------------------------------------------------------
IF ( NOT EXISTS (SELECT * FROM sys.database_principals
WHERE name = N'PolicyAdministratorRole' AND type = 'R'))
BEGIN
CREATE ROLE [PolicyAdministratorRole]
END
ELSE -- if the role exists check to see if it has members
BEGIN
IF NOT EXISTS (SELECT rm.member_principal_id
FROM sys.database_principals dp
INNER JOIN sys.database_role_members rm ON rm.role_principal_id = dp.principal_id
WHERE name = N'PolicyAdministratorRole' AND type = 'R')
BEGIN
-- if the role has no members drop and recreate it
DROP ROLE [PolicyAdministratorRole]
CREATE ROLE [PolicyAdministratorRole]
END
END
GO
-- Policy administrator is also an agent operator
-- because we need to create jobs automatically
EXECUTE sp_addrolemember @rolename = 'SQLAgentOperatorRole' ,
@membername = 'PolicyAdministratorRole'
GO
IF ( NOT EXISTS (SELECT * FROM sys.database_principals
WHERE name = N'ServerGroupAdministratorRole' AND type = 'R'))
BEGIN
CREATE ROLE [ServerGroupAdministratorRole]
END
GO
IF ( NOT EXISTS (SELECT * FROM sys.database_principals
WHERE name = N'ServerGroupReaderRole' AND type = 'R'))
BEGIN
CREATE ROLE [ServerGroupReaderRole]
END
GO
EXECUTE sp_addrolemember @rolename = 'ServerGroupReaderRole' ,
@membername = 'ServerGroupAdministratorRole'
GO
CREATE PROCEDURE #provision_table @short_name sysname, @role_name sysname, @grant_public_select bit
AS
BEGIN
DECLARE @stmt nvarchar(max)
-- revoke table permissions
SELECT @stmt = N'REVOKE DELETE, INSERT, REFERENCES, SELECT, UPDATE, ALTER, CONTROL, TAKE OWNERSHIP
ON [dbo].' + QUOTENAME(@short_name + N'_internal') + ' FROM [public] CASCADE'
EXEC sp_executesql @stmt
-- revoke view permissions
SELECT @stmt = N'REVOKE ALTER, CONTROL, DELETE, INSERT, REFERENCES, SELECT, TAKE OWNERSHIP, UPDATE
ON [dbo].' + QUOTENAME(@short_name ) + ' FROM [public] CASCADE'
EXEC sp_executesql @stmt
-- grant select on view
SELECT @stmt = N'GRANT SELECT ON [dbo].' + QUOTENAME(@short_name)+ ' TO ' + QUOTENAME(@role_name)
EXEC sp_executesql @stmt
if (@grant_public_select != 0)
BEGIN
SELECT @stmt = N'GRANT SELECT ON [dbo].' + QUOTENAME(@short_name)+ ' TO [public]'
EXEC sp_executesql @stmt
END
END
GO
-- public role can view all policy metadata
EXEC #provision_table N'syspolicy_conditions', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_policies', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_policy_categories', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_object_sets', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_target_sets', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_target_set_levels', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_policy_category_subscriptions', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_system_health_state', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_policy_execution_history', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_policy_execution_history_details', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_configuration', N'PolicyAdministratorRole', 1
-- Registered Server information is limited to the ServerGroupReaderRole, with no public access
EXEC #provision_table N'sysmanagement_shared_registered_servers', N'ServerGroupReaderRole', 0
EXEC #provision_table N'sysmanagement_shared_server_groups', N'ServerGroupReaderRole', 0
GO
DROP PROCEDURE #provision_table
GO
CREATE PROCEDURE #provision_sp @name sysname, @role_name sysname
AS
BEGIN
DECLARE @stmt nvarchar(max)
SELECT @stmt = N'REVOKE ALTER, CONTROL, EXECUTE, TAKE OWNERSHIP, VIEW DEFINITION
ON [dbo].' + QUOTENAME(@name) + ' FROM [public] CASCADE'
EXEC sp_executesql @stmt
SELECT @stmt = N'GRANT EXECUTE ON [dbo].' + QUOTENAME(@name)+ ' TO ' + QUOTENAME(@role_name)
EXEC sp_executesql @stmt
END
GO
EXEC #provision_sp N'sp_syspolicy_add_condition', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_condition', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_rename_condition', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_delete_condition', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_add_policy', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_policy', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_rename_policy', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_delete_policy', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_add_target_set', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_target_set', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_add_target_set_level', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_target_set_level', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_add_policy_category_subscription', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_policy_category_subscription', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_delete_policy_category_subscription', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_log_policy_execution_start', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_log_policy_execution_end', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_log_policy_execution_detail', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_add_policy_category', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_rename_policy_category', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_policy_category', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_delete_policy_category', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_add_object_set', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_delete_object_set', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_verify_object_set_identifiers', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_dispatch_event', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_configure', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_purge_history', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_repair_policy_automation', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_purge_health_state', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_create_purge_job', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_set_log_on_success', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_set_config_enabled', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_set_config_history_retention', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_update_shared_registered_server', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_rename_shared_registered_server', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_update_shared_server_group', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_rename_shared_server_group', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_move_shared_registered_server', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_delete_shared_registered_server', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_move_shared_server_group', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_delete_shared_server_group', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_add_shared_registered_server', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_add_shared_server_group', N'ServerGroupAdministratorRole'
GO
DROP PROCEDURE #provision_sp
GO
GRANT EXECUTE ON [dbo].[fn_syspolicy_is_automation_enabled] TO PUBLIC
GO
IF EXISTS (SELECT * from sys.database_principals where name = N'##MS_PolicyEventProcessingLogin##')
DROP USER [##MS_PolicyEventProcessingLogin##]
GO
use master
GO
IF EXISTS (SELECT * from sys.server_principals WHERE name = '##MS_PolicyEventProcessingLogin##')
BEGIN
IF EXISTS (SELECT * from sys.server_triggers WHERE name = N'syspolicy_server_trigger')
DROP TRIGGER [syspolicy_server_trigger] ON ALL SERVER
DROP LOGIN [##MS_PolicyEventProcessingLogin##]
END
go
-- create event processing login with random password
DECLARE @newid uniqueidentifier
SET @newid = NEWID()
DECLARE @password varchar(255)
SELECT @password = QUOTENAME(CONVERT(varchar(255), @newid), '''')
DBCC TRACEON(4606,-1)
EXECUTE( N'CREATE LOGIN [##MS_PolicyEventProcessingLogin##] WITH PASSWORD=N' + @password + '')
DBCC TRACEOFF(4606,-1)
go
-- create t-sql execution login with random password
DECLARE @newid uniqueidentifier
SET @newid = NEWID()
DECLARE @password varchar(255)
SELECT @password = QUOTENAME(CONVERT(varchar(255), @newid), '''')
IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE name = '##MS_PolicyTsqlExecutionLogin##')
BEGIN
DBCC TRACEON(4606,-1)
EXECUTE( N'CREATE LOGIN [##MS_PolicyTsqlExecutionLogin##] WITH PASSWORD=N' + @password + '')
DBCC TRACEOFF(4606,-1)
-- this login is used just for impersonation, no one should be able to connect
ALTER LOGIN [##MS_PolicyTsqlExecutionLogin##] DISABLE
GRANT VIEW ANY DEFINITION TO [##MS_PolicyTsqlExecutionLogin##]
GRANT VIEW SERVER STATE TO [##MS_PolicyTsqlExecutionLogin##]
END
ELSE
BEGIN
ALTER LOGIN [##MS_PolicyTsqlExecutionLogin##] WITH CHECK_POLICY = OFF;
EXECUTE( N'ALTER LOGIN [##MS_PolicyTsqlExecutionLogin##] WITH PASSWORD=N' + @password + '')
ALTER LOGIN [##MS_PolicyTsqlExecutionLogin##] WITH CHECK_POLICY = ON;
END
go
-- this login is used just for impersonation, no one should be able to connect
ALTER LOGIN [##MS_PolicyEventProcessingLogin##] DISABLE
go
USE [msdb]
go
CREATE USER [##MS_PolicyEventProcessingLogin##] FROM LOGIN [##MS_PolicyEventProcessingLogin##]
go
EXEC msdb.sys.sp_addrolemember @rolename = 'PolicyAdministratorRole', @membername = '##MS_PolicyEventProcessingLogin##'
go
GRANT EXECUTE ON [sp_syspolicy_events_reader] TO [##MS_PolicyEventProcessingLogin##]
go
IF NOT EXISTS ( SELECT * FROM sys.database_principals WHERE name = '##MS_PolicyTsqlExecutionLogin##')
BEGIN
CREATE USER [##MS_PolicyTsqlExecutionLogin##] FROM LOGIN [##MS_PolicyTsqlExecutionLogin##]
EXEC msdb.sys.sp_addrolemember @rolename = 'PolicyAdministratorRole', @membername = '##MS_PolicyTsqlExecutionLogin##'
END
GO
USE [master]
go
IF EXISTS (SELECT * from sys.database_principals where name = N'##MS_PolicyEventProcessingLogin##')
DROP USER [##MS_PolicyEventProcessingLogin##]
go
CREATE USER [##MS_PolicyEventProcessingLogin##]
go
GRANT EXECUTE ON [sp_syspolicy_execute_policy] TO [##MS_PolicyEventProcessingLogin##]
go
USE [msdb]
go
PRINT N'Hook up the activation procedure to the queue...'
ALTER QUEUE [syspolicy_event_queue]
WITH ACTIVATION (
STATUS = ON,
MAX_QUEUE_READERS = 1,
PROCEDURE_NAME = [sp_syspolicy_events_reader],
EXECUTE AS N'##MS_PolicyEventProcessingLogin##');
GO
-- if this script runs on an existing installation (e.g in an upgrade) we need to recreate
-- the event notifications and the ddl triggers used for policy automation
exec sys.sp_syspolicy_update_event_notification
exec sys.sp_syspolicy_update_ddl_trigger
GO
USE [msdb]
GO
IF OBJECT_ID('[dbo].[sp_read_settings]', 'P') IS NOT NULL
DROP PROC [dbo].[sp_read_settings]
GO
CREATE PROCEDURE [dbo].[sp_read_settings]
@name sysname = NULL OUTPUT,
@setting_id int = NULL OUTPUT
AS
BEGIN
IF ((@name IS NULL) AND (@setting_id IS NULL)) OR
((@name IS NOT NULL) AND (@setting_id IS NOT NULL))
BEGIN
RAISERROR(14524, -1, -1, '@name', '@setting_id')
RETURN(1) -- Failure
END
IF (@setting_id IS NOT NULL)
BEGIN
SELECT @name = CASE @setting_id
WHEN 1 THEN 'ExtendedProtection'
WHEN 2 THEN 'ForceEncryption'
WHEN 3 THEN 'AcceptedSPNs'
ELSE NULL
END
IF (@name IS NULL) RETURN (2) -- Unknown key
END
ELSE
BEGIN
IF (@name collate SQL_Latin1_General_CP1_CI_AS) != 'ExtendedProtection'
AND (@name collate SQL_Latin1_General_CP1_CI_AS) != 'ForceEncryption'
AND (@name collate SQL_Latin1_General_CP1_CI_AS) != 'AcceptedSPNs'
RETURN (2) -- Unknown key
END
DECLARE @hive nvarchar(32), @key nvarchar(256)
SET @hive=N'HKEY_LOCAL_MACHINE'
SET @key=N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\SuperSocketNetLib'
Execute master.sys.xp_instance_regread @hive, @key, @name
RETURN (0)
END
GO
EXEC sp_MS_marksystemobject 'dbo.sp_read_settings'
GO
-------------------------------------------------------------------------------
-- End policy objects
-------------------------------------------------------------------------------
/**************************************************************/
/* BEGIN DAC SCRIPTS */
/**************************************************************/
-- Note: These should be located before the sysutility objects in instmsdb.sql,
-- because some of the Utility objects depend on the DAC objects.
/**********************************************************************/
/* DAC Functions */
/**********************************************************************/
IF (NOT OBJECT_ID ('[dbo].[fn_sysdac_is_dac_creator]', 'FN') IS NULL)
BEGIN
RAISERROR('Dropping Function [dbo].[fn_sysdac_is_dac_creator]', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysdac_is_dac_creator];
END;
GO
IF (NOT OBJECT_ID ('[dbo].[fn_sysdac_is_login_creator]', 'FN') IS NULL)
BEGIN
RAISERROR('Dropping Function [dbo].[fn_sysdac_is_login_creator]', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysdac_is_login_creator];
END;
GO
IF (NOT OBJECT_ID ('[dbo].[fn_sysdac_is_currentuser_sa]', 'FN') IS NULL)
BEGIN
RAISERROR('Dropping Function [dbo].[fn_sysdac_is_currentuser_sa]', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysdac_is_currentuser_sa];
END;
GO
IF (NOT OBJECT_ID ('[dbo].[fn_sysdac_get_currentusername]', 'FN') IS NULL)
BEGIN
RAISERROR('Dropping Function [dbo].[fn_sysdac_get_currentusername]', 0, 1) WITH NOWAIT;
--
-- Drop the constraints that reference this function
--
DECLARE @dac_constraint_name SYSNAME
DECLARE @sql nvarchar(1000)
-- Find the Default constraint system name on the DAC tables for created_by column.
-- If it's fn_sysdac_get_currentusername, drop this constraint since we are about to drop the function
-- sysdac_instances_internal
SELECT @dac_constraint_name=dc.name
FROM sys.default_constraints dc
JOIN sys.columns c
ON dc.parent_object_id = c.object_id
AND dc.parent_column_id = c.column_id
WHERE dc.parent_object_id = object_id('[dbo].[sysdac_instances_internal]', 'U')
AND dc.definition ='([dbo].[fn_sysdac_get_currentusername]())'
AND c.name='created_by'
IF @dac_constraint_name IS NOT NULL
BEGIN
SELECT @sql = 'ALTER TABLE [dbo].[sysdac_instances_internal] DROP CONSTRAINT ' + QUOTENAME(@dac_constraint_name)
EXEC (@sql)
END
-- sysdac_history_internal
SELECT @dac_constraint_name=dc.name
FROM sys.default_constraints dc
JOIN sys.columns c
ON dc.parent_object_id = c.object_id
AND dc.parent_column_id = c.column_id
WHERE dc.parent_object_id = object_id('[dbo].[sysdac_history_internal]', 'U')
AND dc.definition ='([dbo].[fn_sysdac_get_currentusername]())'
AND c.name='created_by'
IF @dac_constraint_name IS NOT NULL
BEGIN
SELECT @sql = 'ALTER TABLE [dbo].[sysdac_history_internal] DROP CONSTRAINT ' + QUOTENAME(@dac_constraint_name)
EXEC (@sql)
END
--
-- Drop the function
--
DROP FUNCTION [dbo].[fn_sysdac_get_currentusername];
END;
GO
IF (NOT OBJECT_ID ('[dbo].[fn_sysdac_get_username]', 'FN') IS NULL)
BEGIN
RAISERROR('Dropping Function [dbo].[fn_sysdac_get_username]', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysdac_get_username];
END;
GO
/*
Scalar Function: dbo.fn_sysdac_is_dac_creator
Returns a one (1) if the current user is allowed to create DACs
This is generalized in a function for reuse and maintenance
*/
RAISERROR('Creating Function [dbo].[fn_sysdac_is_dac_creator]...', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysdac_is_dac_creator]()
RETURNS int
BEGIN
DECLARE @engineEdition int = CAST(SERVERPROPERTY('EngineEdition') AS int);
DECLARE @isdaccreator int;
-- Check the engine edition
IF (@engineEdition = 5)
BEGIN
-- Sql Azure:
-- is member of dbmanager or is superuser.
SET @isdaccreator = COALESCE(IS_MEMBER('dbmanager'), 0) |
dbo.fn_sysdac_is_currentuser_sa()
END ELSE
BEGIN
-- Standalone, default:
-- is member of dbcreator
/*
We should only require CREATE ANY DATABASE but the database rename
step of creating a DAC requires that we have dbcreator.
If that changes use the code below
-- CREATE ANY DATABASE is what makes somebody a creator
Set @isdaccreator = HAS_PERMS_BY_NAME(null, null, 'CREATE ANY DATABASE')
*/
SET @isdaccreator = COALESCE(is_srvrolemember('dbcreator'), 0)
END
RETURN @isdaccreator;
END
GO
/*
Scalar Function: dbo.fn_sysdac_is_login_creator
Returns a one (1) if the current user is allowed to create Logins
This is generalized in a function for reuse and maintenance
*/
RAISERROR('Creating Function [dbo].[fn_sysdac_is_login_creator]...', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysdac_is_login_creator]()
RETURNS int
BEGIN
DECLARE @engineEdition int = CAST(SERVERPROPERTY('EngineEdition') AS int);
DECLARE @islogincreator int;
-- Check the engine edition
IF (@engineEdition = 5)
BEGIN
-- Sql Azure:
-- is member of loginmanager or is superuser.
SET @islogincreator = COALESCE(IS_MEMBER('loginmanager'), 0) |
dbo.fn_sysdac_is_currentuser_sa()
END ELSE
BEGIN
-- Standalone, default:
-- has ALTER ANY LOGIN permision
SET @islogincreator = HAS_PERMS_BY_NAME(null, null, 'ALTER ANY LOGIN')
END
RETURN @islogincreator;
END
GO
/*
Scalar Function: dbo.fn_sysdac_is_currentuser_sa
Returns a one (1) if the current user is super user
This is generalized in a function for reuse and maintenance
*/
RAISERROR('Creating Function [dbo].[fn_sysdac_is_currentuser_sa]...', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysdac_is_currentuser_sa]()
RETURNS int
BEGIN
DECLARE @engineEdition int = CAST(SERVERPROPERTY('EngineEdition') AS int);
DECLARE @is_sa int;
-- Check the engine edition
IF (@engineEdition = 5)
BEGIN
-- Sql Azure:
-- SID matches with the reserved offset.
-- NOTE: We should get an inbuilt user function from Azure team instead of us querying based on SID.
SET @is_sa = 0
IF((CONVERT(varchar(85), suser_sid(), 2) LIKE '0106000000000164%'))
SET @is_sa = 1
END ELSE
BEGIN
-- Standalone, default:
-- is member of the serverrole 'sysadmin'
SET @is_sa = COALESCE(is_srvrolemember('sysadmin'), 0)
END
RETURN @is_sa;
END
GO
/*
Scalar Function: dbo.fn_sysdac_get_username
Returns the login name of the user with given sid
EXECUTE AS OWNER : This function needs access to sys.sql_logins
This is generalized in a function for reuse and maintenance
*/
RAISERROR('Creating Function [dbo].[fn_sysdac_get_username]...', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysdac_get_username](@user_sid varbinary(85))
RETURNS sysname
WITH EXECUTE AS OWNER
BEGIN
DECLARE @engineEdition int = CAST(SERVERPROPERTY('EngineEdition') AS int);
DECLARE @current_user_name sysname;
IF (@engineEdition = 5)
BEGIN
--SQL Azure does not have syslogins. All the logins reside in sql_logins
SELECT @current_user_name = name FROM sys.sql_logins where sid = @user_sid
END ELSE
BEGIN
--OnPremise engine has both sql and windows logins in syslogins
SELECT @current_user_name = name FROM sys.syslogins where sid = @user_sid
END
RETURN @current_user_name;
END
GO
/*
Scalar Function: dbo.fn_sysdac_get_currentusername
Returns the login name of the current user
This is generalized in a function for reuse and maintenance
*/
RAISERROR('Creating Function [dbo].[fn_sysdac_get_currentusername]...', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysdac_get_currentusername]()
RETURNS sysname
BEGIN
DECLARE @engineEdition int;
DECLARE @current_user_name sysname;
SET @engineEdition = CAST(SERVERPROPERTY('EngineEdition') AS int);
IF (@engineEdition = 5)
BEGIN
--SQL Azure does not have SUSER_SNAME. We need to look in sql_logins to get the user name.
SELECT @current_user_name = dbo.fn_sysdac_get_username(SUSER_SID())
END ELSE
BEGIN
--OnPremise engine has both sql and windows logins - We rely on SUSER_SNAME to find the current user name.
SELECT @current_user_name = SUSER_SNAME()
END
RETURN @current_user_name;
END
GO
/**********************************************************************/
/* DAC TABLES */
/**********************************************************************/
/*
Table dbo.sysdac_instances_internal
Creates one row per one installed DacInstance
*/
IF (OBJECT_ID(N'dbo.sysdac_instances_internal', 'U') IS NULL)
BEGIN
RAISERROR('Creating table [dbo].[sysdac_instances_internal]...', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysdac_instances_internal]
(
instance_id UniqueIdentifier NOT NULL, --unique DAC instance ID of the DacInstance
instance_name sysname NOT NULL, --DacInstance name
type_name sysname NOT NULL, --DacType name
type_version nvarchar(64) NOT NULL,--DacType version
description nvarchar(4000) NULL default (''),
type_stream varbinary(max) NOT NULL, --Package Blob
date_created datetime NOT NULL default GETDATE(),
created_by sysname NOT NULL default dbo.fn_sysdac_get_currentusername(),
CONSTRAINT [PK_sysdac_instances_internal]
PRIMARY KEY CLUSTERED (instance_id),
--instance name is unique
CONSTRAINT [UQ_sysdac_instances_internal]
UNIQUE (instance_name),
);
END
GO
/*
Table dbo.sysdac_history_internal
Holds the information of deployment/deletion steps of DAC instances
*/
IF (OBJECT_ID(N'dbo.sysdac_history_internal', 'U') IS NULL)
BEGIN
RAISERROR('Creating table [dbo].[sysdac_history_internal]...', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysdac_history_internal]
(
action_id int NOT NULL, --action identifier for each attempt of deploy/delete/detach/upgrade
sequence_id int NOT NULL, --step # of deployment/deletion process
instance_id UniqueIdentifier NOT NULL, --unique transaction ID = DAC package id
action_type tinyint NOT NULL, --type of the action being performed
action_type_name AS CASE action_type
WHEN 0 THEN 'deploy'
WHEN 1 THEN 'create'
WHEN 2 THEN 'rename'
WHEN 3 THEN 'register'
WHEN 4 THEN 'create objects'
WHEN 5 THEN 'detach'
WHEN 6 THEN 'delete'
WHEN 7 THEN 'data transfer'
WHEN 8 THEN 'disable constraints'
WHEN 9 THEN 'move data'
WHEN 10 THEN 'enable constraints'
WHEN 11 THEN 'copy permissions'
WHEN 12 THEN 'set readonly'
WHEN 13 THEN 'upgrade'
WHEN 14 THEN 'unregister'
WHEN 15 THEN 'update registration'
WHEN 16 THEN 'set readwrite'
WHEN 17 THEN 'disconnect users'
END,
dac_object_type tinyint NOT NULL, --type of the object affected 0-dacpac,1-login,2-database
dac_object_type_name AS CASE dac_object_type
WHEN 0 THEN 'dacpac'
WHEN 1 THEN 'login'
WHEN 2 THEN 'database'
END,
action_status tinyint NOT NULL, --pending/success/fail
action_status_name AS CASE action_status
WHEN 0 THEN 'not started'
WHEN 1 THEN 'pending'
WHEN 2 THEN 'success'
WHEN 3 THEN 'fail'
WHEN 4 THEN 'rollback'
ELSE NULL
END,
required bit NULL, --indicates if the current step is needed to be committed for success of the action
dac_object_name_pretran sysname, --name of the object before the current step completes
dac_object_name_posttran sysname, --name of the object after the current step completes
sqlscript nvarchar(max) NULL, --sql script for performing the associated object
payload varbinary(max) NULL, --payload data associated with an object. Mostly used for Dacpac
comments varchar(max) NOT NULL, --comments associated with the operation
error_string nvarchar(max) NULL, --error while running associated sql
created_by sysname NOT NULL default dbo.fn_sysdac_get_currentusername(), --login of the user creating the step
date_created datetime NOT NULL default GETDATE(), --datetime at which the step is created
date_modified datetime NOT NULL default GETDATE() --datetime at while the step was last modified
CONSTRAINT [PK_sysdac_history_internal]
PRIMARY KEY CLUSTERED (action_id, sequence_id),
CONSTRAINT [UQ_sysdac_history_internal]
UNIQUE (action_id, dac_object_type, action_type,
dac_object_name_pretran, dac_object_name_posttran),
);
CREATE NONCLUSTERED INDEX IX_sysdac_history_internal
ON sysdac_history_internal(sequence_id, action_status)
END
GO
--
-- Recreate the constraints that reference fn_sysdac_get_currentusername
--
-- sysdac_instances_internal
DECLARE @dac_constraint_name SYSNAME
DECLARE @sql nvarchar(1000)
DECLARE @tablename varchar(50)
SET @tablename = '[dbo].[sysdac_instances_internal]'
SELECT @dac_constraint_name=dc.name
FROM sys.default_constraints dc
JOIN sys.columns c
ON dc.parent_object_id = c.object_id
AND dc.parent_column_id = c.column_id
WHERE dc.parent_object_id = object_id(@tablename, 'U')
AND c.name='created_by'
IF @dac_constraint_name IS NULL
BEGIN
SELECT @sql = 'ALTER TABLE ' + @tablename + ' ADD DEFAULT dbo.fn_sysdac_get_currentusername() FOR created_by';
EXEC (@sql)
END
GO
-- sysdac_history_internal
DECLARE @dac_constraint_name SYSNAME
DECLARE @sql nvarchar(1000)
DECLARE @tablename varchar(50)
SET @tablename = '[dbo].[sysdac_history_internal]'
SELECT @dac_constraint_name=dc.name
FROM sys.default_constraints dc
JOIN sys.columns c
ON dc.parent_object_id = c.object_id
AND dc.parent_column_id = c.column_id
WHERE dc.parent_object_id = object_id(@tablename, 'U')
AND c.name='created_by'
IF @dac_constraint_name IS NULL
BEGIN
SELECT @sql = 'ALTER TABLE ' + @tablename + ' ADD DEFAULT dbo.fn_sysdac_get_currentusername() FOR created_by';
EXEC (@sql)
END
GO
/**********************************************************************/
/* DAC VIEWS */
/**********************************************************************/
/* Clean up any existing views */
IF(NOT OBJECT_ID(N'[dbo].[sysdac_instances]', 'V') IS NULL)
BEGIN
RAISERROR ('Dropping view dbo.sysdac_instances', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysdac_instances;
END;
GO
/*
View : dbo.sysdac_instances
Returns one row for each package installed in the system. The list is filtered
based on the callers permisions.
sysadmin: sees all information for all instances
dbo's: sees all information for dacs in databases they own, limited information for all other instances
public: sees limited information for all packges
*/
RAISERROR('Creating View [dbo].[sysdac_instances]...', 0, 1) WITH NOWAIT;
GO
CREATE VIEW [dbo].[sysdac_instances]
AS
SELECT
-- this must be locked down because we use instance_id visability as a security gate
case
when (dbo.fn_sysdac_is_currentuser_sa() = 1) then dac_instances.instance_id
when sd.owner_sid = SUSER_SID() then dac_instances.instance_id
else NULL
end as instance_id,
dac_instances.instance_name,
dac_instances.type_name,
dac_instances.type_version,
dac_instances.description,
case
when (dbo.fn_sysdac_is_currentuser_sa() = 1) then dac_instances.type_stream
when sd.owner_sid = SUSER_SID() then dac_instances.type_stream
else NULL
end as type_stream,
dac_instances.date_created,
dac_instances.created_by,
dac_instances.instance_name as database_name
FROM sysdac_instances_internal dac_instances
LEFT JOIN sys.databases sd
ON dac_instances.instance_name = sd.name
GO
/**********************************************************************/
/* DAC Stored Procedures */
/**********************************************************************/
/*Drop existing Stored Procedures*/
IF (NOT OBJECT_ID ('dbo.sp_sysdac_add_history_entry', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_add_history_entry', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_add_history_entry;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_add_instance', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_add_instance', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_add_instance;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_update_instance', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_update_instance', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_update_instance;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_upgrade_instance', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_upgrade_instance', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_upgrade_instance;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_update_history_entry', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_update_history_entry', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_update_history_entry;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_delete_instance', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_delete_instance', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_delete_instance;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_delete_history', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_delete_history', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_delete_history;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_rename_database', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_rename_database', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_rename_database;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_drop_database', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_drop_database', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_drop_database;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_drop_login', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_drop_login', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_drop_login;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_ensure_dac_creator', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_ensure_dac_creator', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_ensure_dac_creator;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_rollback_all_pending_objects', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_rollback_all_pending_objects', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_rollback_all_pending_objects;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_rollback_pending_object', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_rollback_pending_object', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_rollback_pending_object;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_setreadonly_database', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_setreadonly_database', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_setreadonly_database;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_resolve_pending_entry', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_resolve_pending_entry', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_resolve_pending_entry;
END;
GO
IF (NOT OBJECT_ID ('dbo.sp_sysdac_rollback_committed_step', 'P') IS NULL)
BEGIN
RAISERROR('Dropping Stored Procedure sp_sysdac_rollback_committed_step', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysdac_rollback_committed_step;
END;
GO
/*
Procedure [sp_sysdac_ensure_dac_creator]
This sproc checks the caller is a dac creator and raise's an error if not
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_ensure_dac_creator]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysdac_ensure_dac_creator
as
BEGIN
-- only users that can create a dac can add parts
IF (dbo.fn_sysdac_is_dac_creator() != 1)
BEGIN
RAISERROR(36010, -1, -1);
RETURN(1); -- failure
END
END
go
/*
Procedure [sp_sysdac_add_instance]
This proc creates a new DacInstance in dbo.sysdac_instances_internal table
Parameters:
@type_name - Name of the Dac type
@type_version - Version of the Dac type
@instance_name - Name of the Dac Instance
@instance_id - Guid identification of a Dac instance
@description - Dac type description
@type_stream - package content of the dac type
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_add_instance]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_add_instance]
@type_name sysname,
@instance_id UniqueIdentifier = NULL,
@instance_name sysname,
@type_version NVARCHAR(64) = NULL,
@description nvarchar(4000) = N'',
@type_stream varbinary(max)
AS
SET NOCOUNT ON;
BEGIN
DECLARE @retval INT
DECLARE @null_column sysname
SET @null_column = NULL
IF (@type_name IS NULL OR @type_name = N'')
SET @null_column = '@type_name'
ELSE IF (@instance_name IS NULL OR @instance_name = N'')
SET @null_column = '@instance_name'
ELSE IF (@instance_id IS NULL )
SET @null_column = '@instance_id'
ELSE IF( @type_version = N'')
SET @null_column = '@type_version'
ELSE IF( @type_stream IS NULL)
SET @null_column = '@type_stream'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysdac_add_instance')
RETURN(1)
END
-- only users that can create a dac can add instances
if (dbo.fn_sysdac_is_dac_creator() != 1)
BEGIN
RAISERROR(36010, -1, -1);
RETURN(1); -- failure
END
--instance_name is unique
IF EXISTS (SELECT * FROM dbo.sysdac_instances_internal WHERE instance_name = @instance_name)
BEGIN
RAISERROR(36001, -1, -1, 'DacInstance', @instance_name)
RETURN(1)
END
--Ensure that the database being referred exists
IF NOT EXISTS (SELECT * from sys.sysdatabases WHERE name = @instance_name)
BEGIN
RAISERROR(36005, -1, -1, @instance_name)
RETURN(1)
END
INSERT INTO [dbo].[sysdac_instances_internal]
(instance_id, type_name, instance_name, type_version, description, type_stream)
VALUES
(@instance_id, @type_name, @instance_name, @type_version, @description, @type_stream)
SELECT @retval = @@error
RETURN(@retval)
END
GO
/*
Procedure [sp_sysdac_update_instance]
This proc updates an existing DacInstance in dbo.sysdac_instances_internal table
Parameters:
@type_name - Name of the Dac type. If NULL, then type_name will not be updated.
@type_version - Version of the Dac type
@instance_name - Name of the Dac Instance. If NULL, then instance_name will not be updated.
@instance_id - Guid identification of a Dac instance
@description - Dac type description
@type_stream - package content of the dac type
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_update_instance]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_update_instance]
@type_name sysname,
@instance_id UniqueIdentifier = NULL,
@instance_name sysname,
@type_version NVARCHAR(64) = NULL,
@description nvarchar(4000) = N'',
@type_stream varbinary(max)
AS
SET NOCOUNT ON;
BEGIN
DECLARE @retval INT
DECLARE @null_column sysname
SET @null_column = NULL
IF (@type_name = N'')
SET @null_column = '@type_name'
ELSE IF (@instance_name = N'')
SET @null_column = '@instance_name'
ELSE IF (@instance_id IS NULL )
SET @null_column = '@instance_id'
ELSE IF( @type_version = N'')
SET @null_column = '@type_version'
ELSE IF( @type_stream IS NULL)
SET @null_column = '@type_stream'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysdac_add_instance')
RETURN(1)
END
-- Ensure that the package being referred to exists by using the package view. We only continue if we can see
-- the specified package. The package will only be visible if we are the associated dbo or sysadmin and it exists
IF NOT EXISTS (SELECT * from dbo.sysdac_instances WHERE instance_id = @instance_id)
BEGIN
RAISERROR(36004, -1, -1)
RETURN(1)
END
UPDATE sysdac_instances_internal SET
type_name = ISNULL(@type_name, type_name),
instance_name = ISNULL(@instance_name, instance_name),
type_version = @type_version,
description = @description,
type_stream = @type_stream
WHERE instance_id = @instance_id
SELECT @retval = @@error
RETURN(@retval)
END
GO
/*
Procedure [sp_sysdac_add_history_entry]
This proc creates a new row in dbo.sysdac_history_internal table
Parameters:
@sequence_id --step # of deployment/deletion process
@instance_id --unique transaction ID = DAC package id
@part_name --name of the dacpart corresponding to this part
@action_type --type of the action being performed 0-deploy 1-detach 2-delete
@dac_object_type --type of the object affected 0-dacpac,1-login,2-database
@required -- indicates if the steps is needed(value of 1) to be committed for the success of the action
@dac_object_name_pretran --name of the object before the current step completes
@dac_object_name_posttran --name of the object after the current step completes
@sqlscript --sql script for performing the associated object
@payload --payload data associated with an object. Mostly used for Dacpac
@comments --comments associated with the history
@error_string --error while running associated sql
@action_id --action identifier for each attempt of deploy/delete/detach/upgrade
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_add_history_entry]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_add_history_entry]
@sequence_id int,
@instance_id UniqueIdentifier = NULL,
@action_type tinyint = NULL,
@action_status tinyint = NULL,
@dac_object_type tinyint = NULL,
@required bit = NULL,
@dac_object_name_pretran sysname = N'',
@dac_object_name_posttran sysname = N'',
@sqlscript nvarchar(max) = N'',
@payload varbinary(max) = NULL,
@comments varchar(max) = N'',
@error_string nvarchar(max) = N'',
@action_id int = NULL OUTPUT
AS
SET NOCOUNT ON;
BEGIN
DECLARE @retval INT
DECLARE @null_column sysname
SET @null_column = NULL
IF (@instance_id IS NULL)
SET @null_column = '@instance_id'
ELSE IF (@action_type IS NULL)
SET @null_column = '@action_type'
ELSE IF (@action_status IS NULL)
SET @null_column = '@action_status'
ELSE IF (@dac_object_type IS NULL)
SET @null_column = '@dac_object_type'
ELSE IF (@required IS NULL)
SET @null_column = '@required'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysdac_add_history_entry')
RETURN(1)
END
-- comments is optional. make sure it is non-null
IF (@comments IS NULL)
BEGIN
SET @comments = N''
END
--- Ensure the user is either a db_creator or that the package being referred is visible via the package view.
--- For non-dbcreators, the package will only be visible if we are the associated dbo or sysadmin and the instance row exists
IF ((dbo.fn_sysdac_is_dac_creator() != 1) AND
(NOT EXISTS (SELECT * from dbo.sysdac_instances WHERE instance_id = @instance_id)))
BEGIN
RAISERROR(36004, -1, -1)
RETURN(1)
END
BEGIN TRAN
--If the action_id value is not set by the user, this is a new entry and the proc
--should calculate the next value which is one more than the current max
IF (@action_id IS NULL)
BEGIN
SET @action_id = (
SELECT ISNULL(MAX(action_id) + 1, 0)
FROM dbo.sysdac_history_internal WITH (UPDLOCK, HOLDLOCK))
END
INSERT INTO [dbo].[sysdac_history_internal]
(action_id, sequence_id, instance_id, action_type, dac_object_type, action_status, required,
dac_object_name_pretran, dac_object_name_posttran, sqlscript, payload, comments, error_string)
VALUES
(@action_id, @sequence_id, @instance_id, @action_type, @dac_object_type, @action_status, @required,
@dac_object_name_pretran, @dac_object_name_posttran, @sqlscript, @payload, @comments, @error_string)
COMMIT
SELECT @retval = @@error
RETURN(@retval)
END
GO
/*
Procedure [sp_sysdac_delete_instance]
This proc deletes DacInstance with the input instance_id in dbo.sysdac_instances_internal table
Parameters:
@instance_id - Guid identifier of a Dac Package
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_delete_instance]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_delete_instance]
@instance_id UniqueIdentifier
AS
SET NOCOUNT ON;
BEGIN
DECLARE @retval INT
DECLARE @partId INT
IF @instance_id IS NULL
BEGIN
RAISERROR(14043, -1, -1, 'instance_id', 'sp_sysdac_delete_instance')
RETURN(1)
END
-- Ensure that the package being referred to exists by using the package view. We only continue if we can see
-- the specified package. The package will only be visible if we are the associated dbo or sysadmin and it exists
IF NOT EXISTS (SELECT * from dbo.sysdac_instances WHERE instance_id = @instance_id)
BEGIN
RAISERROR(36004, -1, -1)
RETURN(1)
END
--Delete the entry of DacInstance
DELETE FROM sysdac_instances_internal WHERE instance_id=@instance_id
SELECT @retval = @@error
RETURN(@retval)
END
GO
/*
Procedure [sp_sysdac_delete_history]
This proc deletes History entries in the dbo.sysdac_history_internal table
Parameters:
@dac_instance_name - Name of the dac instance whose history is intended to be purged.
If it's null, all entries that the user can delete 'or' orphan entries shall be purged.
@older_than - DateTime to limit the rows affected. Rows whose modified datetime < @older_than will only be considered.
If it's null, current datetime(GETDATE()) is used.
User needs to either own the DAC or be sysadmin to purge the entries or else, purging will not succeed.
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_delete_history]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_delete_history]
@dac_instance_name sysname,
@older_than datetime
AS
SET NOCOUNT ON;
BEGIN
DECLARE @retval INT
DECLARE @instanceId UniqueIdentifier
SELECT @older_than = COALESCE(@older_than, GETDATE())
IF @dac_instance_name IS NULL
BEGIN
-- Delete everyone who is not orphaned that you have visibility to
DELETE FROM dbo.sysdac_history_internal
WHERE instance_id IN (SELECT instance_id FROM dbo.sysdac_instances)
AND (date_modified < @older_than)
-- Also remove orphans (note that we need to look into sysdac_instances_internal table)
DELETE FROM dbo.sysdac_history_internal
WHERE instance_id NOT IN( SELECT instance_id FROM dbo.sysdac_instances_internal)
AND (date_modified < @older_than)
END
ELSE
BEGIN
-- Delete all entries that the user can view (i.e own the DAC or be sysadmin)
DELETE FROM dbo.sysdac_history_internal
WHERE instance_id IN (
SELECT instance_id
FROM dbo.sysdac_instances
WHERE instance_name = @dac_instance_name)
AND (date_modified < @older_than)
END
SELECT @retval = @@error
RETURN(@retval)
END
GO
/*
Procedure [sp_sysdac_upgrade_instance]
This proc upgrades existing DacInstance metadata with the new version DacInstance.
Parameters:
@source_instance_id - Instance identifier of the original Dac Instance
@instance_id - identifer of the new Dac Instance that's installed as a temporary instance
@instance_name - name of the new Dac Instance that's installed as a temporary instance
@database_name - database name of the original DAC
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_upgrade_instance]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_upgrade_instance]
@source_instance_id UniqueIdentifier = NULL,
@instance_id UniqueIdentifier = NULL,
@instance_name sysname,
@database_name sysname
AS
SET NOCOUNT ON;
BEGIN
DECLARE @retval INT
DECLARE @null_column sysname
SET @null_column = NULL
IF (@source_instance_id IS NULL)
SET @null_column = '@source_instance_id'
ELSE IF (@instance_id IS NULL )
SET @null_column = '@instance_id'
ELSE IF( @database_name IS NULL)
SET @null_column = '@database_name'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysdac_upgrade_instance')
RETURN(1)
END
-- Ensure that the package being referred to exists by using the package view. We only continue if we can see
-- the specified package. The package will only be visible if we are the associated dbo or sysadmin and it exists
IF NOT EXISTS (SELECT * from dbo.sysdac_instances WHERE instance_id = @instance_id)
BEGIN
RAISERROR(36004, -1, -1)
RETURN(1)
END
--Ensure that the package being referred exists
IF NOT EXISTS (SELECT * from dbo.sysdac_instances_internal WHERE instance_id = @instance_id)
BEGIN
RAISERROR(36004, -1, -1)
RETURN(1)
END
BEGIN TRAN
--Delete the source DacInstance first
EXEC dbo.sp_sysdac_delete_instance @instance_id = @instance_id
--Update the new version DacInstance metadata with the original DacInstance
UPDATE [dbo].[sysdac_instances_internal]
SET instance_id = @instance_id,
instance_name = @instance_name
WHERE instance_id = @source_instance_id
COMMIT
SELECT @retval = @@error
RETURN(@retval)
END
GO
/*
Procedure [sp_sysdac_drop_database]
This proc drops DAC databases
Parameters
@database_name : Name of the Database to be dropped
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_drop_database]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_drop_database]
@database_name sysname
AS
SET NOCOUNT ON;
BEGIN
IF EXISTS(SELECT name FROM sys.databases WHERE name = @database_name)
BEGIN
DECLARE @engineEdition int = CAST(SERVERPROPERTY('EngineEdition') AS int);
DECLARE @quoteddbname nvarchar(258)
SET @quoteddbname = QUOTENAME(@database_name)
DECLARE @sqlstatement nvarchar(1000)
IF (@engineEdition != 5)
BEGIN
SET @sqlstatement = 'ALTER DATABASE ' + @quoteddbname + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE'
EXEC (@sqlstatement)
END
SET @sqlstatement = 'DROP DATABASE ' + @quoteddbname
IF (@engineEdition = 5)
BEGIN
DECLARE @dbname SYSNAME
SET @dbname = db_name()
RAISERROR (36012, 0, 1, @dbname, @sqlstatement);
SELECT @dbname as databasename, @sqlstatement as sqlscript
END
ELSE
BEGIN
EXEC (@sqlstatement)
END
END
RETURN(@@error)
END
GO
/*
Procedure [sp_sysdac_rename_database]
This proc renames DAC databases
Parameters
@@database_name : original name of the database
@new_name : new name of the database
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_rename_database]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_rename_database]
@database_name sysname,
@new_name sysname
AS
SET NOCOUNT ON;
BEGIN
DECLARE @sqlstatement nvarchar(1000)
-- Alter the database to single user mode
DECLARE @quoted_database_name nvarchar(258)
SET @quoted_database_name = QUOTENAME(@database_name)
SET @sqlstatement = 'ALTER DATABASE ' + @quoted_database_name + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE'
EXEC (@sqlstatement)
-- Rename the database
EXEC sp_rename @objname=@quoted_database_name, @newname=@new_name, @objtype='DATABASE'
-- Revert the database back to multi user mode
DECLARE @quoted_new_name nvarchar(258)
SET @quoted_new_name = QUOTENAME(@new_name)
SET @sqlstatement = 'ALTER DATABASE ' + @quoted_new_name + ' SET MULTI_USER WITH ROLLBACK IMMEDIATE'
EXEC (@sqlstatement)
RETURN(@@error)
END
GO
/*
Procedure [sp_sysdac_setreadonly_database]
This proc renames DAC databases
Parameters
@database_name : original name of the database
@readonly : (0) to set readonly, (1) to set readwrite. Default value is 0
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_setreadonly_database]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_setreadonly_database]
@database_name sysname,
@readonly bit = 0
AS
SET NOCOUNT ON;
BEGIN
DECLARE @sqlstatement nvarchar(1000)
DECLARE @quoted_database_name nvarchar(258)
SET @quoted_database_name = QUOTENAME(@database_name)
IF (@readonly = 0)
SET @sqlstatement = 'ALTER DATABASE ' + @quoted_database_name + ' SET READ_ONLY WITH ROLLBACK IMMEDIATE'
ELSE IF (@readonly = 1)
SET @sqlstatement = 'ALTER DATABASE ' + @quoted_database_name + ' SET READ_WRITE WITH ROLLBACK IMMEDIATE'
EXEC (@sqlstatement)
RETURN(@@error)
END
GO
/*
Procedure [sp_sysdac_update_history_entry]
This proc update entry in dbo.sysdac_history_internal table
Parameters:
@action_id --action identifier for each attempt of deploy/delete/detach/upgrade
@instance_id --unique transaction ID = DAC package id
@action_type --type of the action being performed 0-deploy 1-detach 2-delete
@dac_object_type --type of the object affected 0-dacpac,1-login,2-database
@action_status --pending/success/fail
@dac_object_name_pretran --name of the object before the current step completes
@dac_object_name_posttran --name of the object after the current step completes
@sqlscript --sql script for performing the associated object
@error_string --error while running associated sql
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_update_history_entry]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_update_history_entry]
@action_id int,
@instance_id UniqueIdentifier = NULL,
@action_type tinyint = NULL,
@dac_object_type tinyint = NULL,
@action_status tinyint = NULL,
@dac_object_name_pretran sysname = N'',
@dac_object_name_posttran sysname = N'',
@sqlscript nvarchar(max) = N'',
@error_string nvarchar(max) = N''
AS
SET NOCOUNT ON;
BEGIN
DECLARE @retval INT
DECLARE @null_column sysname
SET @null_column = NULL
IF (@instance_id IS NULL)
SET @null_column = '@instance_id'
ELSE IF (@action_type IS NULL)
SET @null_column = '@action_type'
ELSE IF (@dac_object_type IS NULL)
SET @null_column = '@dac_object_type'
ELSE IF (@action_status IS NULL) --action_status should be non-pending (success/failure)
SET @null_column = '@action_status'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysdac_update_history_entry')
RETURN(1)
END
-- Only allow users who created history entry or 'sysadmins' to update the row
DECLARE @username SYSNAME
SET @username = (SELECT created_by
FROM dbo.sysdac_history_internal
WHERE instance_id = @instance_id AND
action_id = @action_id AND
action_type = @action_type AND
dac_object_type = @dac_object_type AND
dac_object_name_pretran = @dac_object_name_pretran AND
dac_object_name_posttran = @dac_object_name_posttran)
IF ((@username != [dbo].[fn_sysdac_get_currentusername]()) AND ([dbo].[fn_sysdac_is_currentuser_sa]() != 1))
BEGIN
RAISERROR(36011, -1, -1);
RETURN(1); -- failure
END
UPDATE [dbo].[sysdac_history_internal]
SET
action_status = @action_status,
sqlscript = @sqlscript,
error_string = @error_string,
date_modified = (SELECT GETDATE())
WHERE
action_id = @action_id AND
action_type = @action_type AND
dac_object_type = @dac_object_type AND
dac_object_name_pretran = @dac_object_name_pretran AND
dac_object_name_posttran = @dac_object_name_posttran
SELECT @retval = @@error
RETURN(@retval)
END
GO
/*
Procedure [sp_sysdac_resolve_pending_entry]
This proc resolves a pending entry to either completed or failed
Parameters:
@action_id --action identifier for each attempt of deploy/delete/detach/upgrade
@sequence_id --step # of deployment/deletion process
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_resolve_pending_entry]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_resolve_pending_entry]
@action_id INT,
@sequence_id INT
AS
SET NOCOUNT ON;
BEGIN
DECLARE @null_column sysname
SET @null_column = NULL
IF (@action_id IS NULL)
SET @null_column = '@action_id'
ELSE IF (@sequence_id IS NULL)
SET @null_column = '@sequence_id'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysdac_resolve_pending_entry')
RETURN(1)
END
DECLARE @instance_id UNIQUEIDENTIFIER
DECLARE @action_type TINYINT
DECLARE @dac_object_type TINYINT
DECLARE @action_status TINYINT
DECLARE @dac_object_name_pretran SYSNAME
DECLARE @dac_object_name_posttran SYSNAME
SELECT @instance_id = instance_id,
@action_type = action_type,
@dac_object_type = dac_object_type,
@dac_object_name_pretran = dac_object_name_pretran,
@dac_object_name_posttran = dac_object_name_posttran
FROM sysdac_history_internal
WHERE action_id = @action_id AND sequence_id = @sequence_id
--Below are the constants set based on history table
DECLARE @create TINYINT
DECLARE @rename TINYINT
DECLARE @database TINYINT
DECLARE @success TINYINT
DECLARE @rollback TINYINT
DECLARE @fail TINYINT
DECLARE @register TINYINT
DECLARE @unregister TINYINT
DECLARE @upgrade TINYINT
DECLARE @readonly TINYINT
DECLARE @readwrite TINYINT
DECLARE @disconnectusers TINYINT
DECLARE @readonlymode INT
SET @create = 1
SET @rename = 2
SET @database = 2
SET @success = 2
SET @rollback = 4
SET @fail = 3
SET @register = 3
SET @unregister = 14
SET @upgrade = 15
SET @readonly = 12
SET @readwrite = 16
SET @disconnectusers = 17
SET @readonlymode = 1024
SET @action_status = @fail --initialize result of the action to failure and adjust if below cases succeed!
IF @action_type = @create AND @dac_object_type = @database --database create
BEGIN
IF EXISTS(SELECT 1 FROM sys.sysdatabases WHERE name = @dac_object_name_pretran)
SET @action_status = @success
END
ELSE IF @action_type = @rename AND @dac_object_type = @database --database rename
BEGIN
IF (EXISTS(SELECT 1 FROM sys.sysdatabases WHERE name = @dac_object_name_posttran)) AND
(NOT EXISTS(SELECT 1 FROM sys.sysdatabases WHERE name = @dac_object_name_pretran))
SET @action_status = @success
END
ELSE IF @action_type = @register --register DAC
BEGIN
IF (EXISTS(SELECT 1 FROM dbo.sysdac_instances_internal WHERE instance_name = @dac_object_name_pretran))
SET @action_status = @success
END
ELSE IF @action_type = @unregister --unregister DAC
BEGIN
IF (NOT EXISTS(SELECT 1 FROM dbo.sysdac_instances_internal WHERE instance_name = @dac_object_name_pretran))
SET @action_status = @success
END
ELSE IF @action_type = @upgrade --upgrade DAC
BEGIN
IF (EXISTS(SELECT 1 FROM dbo.sysdac_instances_internal WHERE instance_name = @dac_object_name_posttran)) AND
(NOT EXISTS(SELECT 1 FROM dbo.sysdac_instances_internal WHERE instance_name = @dac_object_name_pretran))
SET @action_status = @success
END
ELSE IF @action_type = @readonly OR @action_type = @disconnectusers -- readonly/disconnect users state
BEGIN
IF (EXISTS(SELECT 1 FROM sys.sysdatabases
WHERE ((status & @readonlymode) = @readonlymode) AND name=@dac_object_name_pretran))
SET @action_status = @success
END
ELSE IF @action_type = @readwrite -- readwrite state
BEGIN
IF (EXISTS(SELECT 1 FROM sys.sysdatabases
WHERE ((status & @readonlymode) != @readonlymode) AND name=@dac_object_name_pretran))
SET @action_status = @success
END
UPDATE sysdac_history_internal
SET action_status = @action_status
WHERE action_id = @action_id AND sequence_id = @sequence_id
END
GO
/*
Procedure [sp_sysdac_rollback_committed_step]
This proc rollsback a given committed step.
Parameters:
@action_id --action identifier for each attempt of deploy/delete/detach/upgrade
@sequence_id --step # of deployment/deletion process
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_rollback_committed_step]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_rollback_committed_step]
@action_id INT,
@sequence_id INT
AS
SET NOCOUNT ON;
BEGIN
DECLARE @retval INT
DECLARE @null_column sysname
SET @null_column = NULL
IF (@action_id IS NULL)
SET @null_column = '@action_id'
ELSE IF (@sequence_id IS NULL)
SET @null_column = '@sequence_id'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysdac_rollback_committed_step')
RETURN(1)
END
DECLARE @instance_id UNIQUEIDENTIFIER
DECLARE @part_name NVARCHAR(128)
DECLARE @action_type TINYINT
DECLARE @dac_object_type TINYINT
DECLARE @action_status TINYINT
DECLARE @dac_object_name_pretran SYSNAME
DECLARE @dac_object_name_posttran SYSNAME
DECLARE @sqlstatement NVARCHAR(1000)
SELECT @instance_id = instance_id,
@action_id = action_id,
@action_type = action_type,
@sequence_id = sequence_id,
@dac_object_type = dac_object_type,
@action_status = action_status,
@dac_object_name_pretran = dac_object_name_pretran,
@dac_object_name_posttran = dac_object_name_posttran
FROM sysdac_history_internal
WHERE action_id = @action_id AND sequence_id = @sequence_id
--Below are the constants set based on history table
DECLARE @create TINYINT
DECLARE @rename TINYINT
DECLARE @register TINYINT
DECLARE @database TINYINT
DECLARE @rollback TINYINT
DECLARE @rollback_pending TINYINT
DECLARE @rollback_success TINYINT
DECLARE @setreadonly TINYINT
DECLARE @setreadwrite TINYINT
SET @create = 1
SET @rename = 2
SET @register = 3
SET @database = 2
SET @rollback = 4
SET @rollback_pending = 0
SET @rollback_success = 1
SET @setreadonly = 12
SET @setreadwrite = 16
IF @action_type = @create AND @dac_object_type = @database --database create
BEGIN
RAISERROR(N'%d, %d, %s', -1, 1, @sequence_id, @rollback_pending, NULL) WITH NOWAIT
EXEC dbo.sp_sysdac_drop_database @database_name = @dac_object_name_pretran
RAISERROR(N'%d, %d, %s', -1, 1, @sequence_id, @rollback_success, NULL) WITH NOWAIT
END
ELSE IF @action_type = @rename AND @dac_object_type = @database --database rename
BEGIN
RAISERROR(N'%d, %d, %s', -1, 1, @sequence_id, @rollback_pending, NULL) WITH NOWAIT
EXEC dbo.sp_sysdac_rename_database @dac_object_name_posttran, @dac_object_name_pretran
RAISERROR(N'%d, %d, %s', -1, 1, @sequence_id, @rollback_success, NULL) WITH NOWAIT
END
ELSE IF @action_type = @register --register DAC
BEGIN
SET @instance_id = (
SELECT instance_id
FROM dbo.sysdac_instances_internal
WHERE instance_name = @dac_object_name_pretran)
RAISERROR(N'%d, %d, %s', -1, 1, @sequence_id, @rollback_pending, NULL) WITH NOWAIT
EXEC dbo.sp_sysdac_delete_instance @instance_id = @instance_id
RAISERROR(N'%d, %d, %s', -1, 1, @sequence_id, @rollback_success, NULL) WITH NOWAIT
END
ELSE IF @action_type = @setreadonly --readonly step
BEGIN
RAISERROR(N'%d, %d, %s', -1, 1, @sequence_id, @rollback_pending, NULL) WITH NOWAIT
EXEC dbo.sp_sysdac_setreadonly_database @database_name = @dac_object_name_pretran, @readonly = 1
RAISERROR(N'%d, %d, %s', -1, 1, @sequence_id, @rollback_success, NULL) WITH NOWAIT
END
ELSE IF @action_type = @setreadwrite --readonly step
BEGIN
RAISERROR(N'%d, %d, %s', -1, 1, @sequence_id, @rollback_pending, NULL) WITH NOWAIT
EXEC dbo.sp_sysdac_setreadonly_database @database_name = @dac_object_name_pretran, @readonly = 0
RAISERROR(N'%d, %d, %s', -1, 1, @sequence_id, @rollback_success, NULL) WITH NOWAIT
END
--mark the entry as rolledback
UPDATE sysdac_history_internal
SET action_status = @rollback
WHERE action_id = @action_id AND sequence_id = @sequence_id
SELECT @retval = @@error
RETURN(@retval)
END
GO
/*
Procedure [sp_sysdac_rollback_pending_object]
This proc rollsback the pending object of a given action id.
Parameters:
@action_id --action identifier for each attempt of deploy/delete/detach/upgrade
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_rollback_pending_object]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_rollback_pending_object]
@action_id INT
AS
SET NOCOUNT ON;
BEGIN
IF (@action_id IS NULL)
BEGIN
RAISERROR(14043, -1, -1, '@action_id', 'sp_sysdac_rollback_pending_object')
RETURN(1)
END
DECLARE @sequence_id INT
DECLARE @action_status TINYINT
--Below are the constants set based on history table
DECLARE @header_id bit
DECLARE @pending TINYINT
DECLARE @success TINYINT
DECLARE @true bit
DECLARE @rollback TINYINT
DECLARE @fail TINYINT
DECLARE @rollback_failure TINYINT
SET @header_id = 0
SET @pending = 1
SET @success = 2
SET @true = 1
SET @rollback = 4
SET @fail = 3
SET @rollback_failure = 2
--if step 0 is not pending, exit
IF ((SELECT action_status
FROM sysdac_history_internal
WHERE action_id = @action_id AND sequence_id = @header_id) != @pending)
RETURN;
--STEP 1. Resolve pending entry
SET @sequence_id = (SELECT TOP 1 sequence_id
FROM sysdac_history_internal
WHERE sequence_id != @header_id AND action_id = @action_id AND action_status = @pending)
IF (@sequence_id IS NOT NULL)
EXEC dbo.sp_sysdac_resolve_pending_entry @action_id = @action_id, @sequence_id = @sequence_id
--check if all required steps are committed(success). If so, mark the action success and return!
IF NOT EXISTS (SELECT 1
FROM sysdac_history_internal
WHERE action_id = @action_id AND sequence_id != @header_id AND required = @true AND action_status != @success)
BEGIN
UPDATE dbo.sysdac_history_internal
SET action_status = @success
WHERE action_id = @action_id AND sequence_id = @header_id
RETURN
END
BEGIN TRY
--STEP 2. rollback commit entries
WHILE EXISTS( SELECT 1
FROM sysdac_history_internal
WHERE action_status = @success AND action_id = @action_id AND sequence_id > 0)
BEGIN
SELECT TOP 1 @sequence_id = sequence_id,
@action_status = action_status
FROM sysdac_history_internal
WHERE action_status = @success AND action_id = @action_id AND sequence_id != @header_id
ORDER BY sequence_id DESC
EXEC dbo.sp_sysdac_rollback_committed_step @action_id = @action_id, @sequence_id = @sequence_id
END
--Mark the header entry as rolledback
SET @action_status = @rollback
END TRY
BEGIN CATCH
DECLARE @error_message NVARCHAR(4000);
SELECT @error_message = ERROR_MESSAGE()
RAISERROR(N'%d, %d, %s', -1, 1, @sequence_id, @rollback_failure, @error_message) WITH NOWAIT
--Mark the header entry as failed
SET @action_status = @fail
END CATCH
--STEP 3. Mark the header entry with final action status
UPDATE dbo.sysdac_history_internal
SET action_status = @action_status
WHERE action_id = @action_id AND sequence_id = @header_id
END
GO
/*
Procedure [sp_sysdac_rollback_all_pending_objects]
This proc rollsback all the pending actions.
Parameters:
@return_scripts -- if set to 1, stored procedure will return as a resultset
a set of sql scripts needed to be additionally executed to complete the rollback.
Rollback procedure might not be able to execute them due to sql server limitations.
*/
RAISERROR('Creating procedure [dbo].[sp_sysdac_rollback_all_pending_objects]...', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysdac_rollback_all_pending_objects] (@return_scripts TINYINT = 0)
AS
SET NOCOUNT ON;
BEGIN
DECLARE @action_id INT
DECLARE @sequence_id INT
--Below are the constants set based on history table
DECLARE @header_id bit
DECLARE @pending TINYINT
SET @header_id = 0
SET @pending = 1
CREATE TABLE #additional_scripts(databasename sysname, sqlscript VARCHAR(MAX))
WHILE EXISTS (SELECT 1 FROM sysdac_history_internal WHERE sequence_id = @header_id AND action_status = @pending)
BEGIN
SET @action_id = (SELECT TOP 1 action_id FROM sysdac_history_internal WHERE sequence_id = @header_id AND action_status = @pending)
INSERT INTO #additional_scripts
EXEC dbo.sp_sysdac_rollback_pending_object @action_id = @action_id
END
IF (@return_scripts = 1)
BEGIN
SELECT databasename, sqlscript FROM #additional_scripts
END
END
GO
-----------------------------------------------------------
-- Security for Dac objects
-----------------------------------------------------------
-- everybody can see the dacs view. These are filtered views so no info disclosure by it being granted to public
GRANT SELECT ON dbo.sysdac_instances to PUBLIC
-- everybody can see if they are a dac creator or not
GRANT EXECUTE ON dbo.fn_sysdac_is_dac_creator to PUBLIC
GRANT EXECUTE ON dbo.fn_sysdac_is_login_creator to PUBLIC
GRANT EXECUTE ON dbo.fn_sysdac_is_currentuser_sa to PUBLIC
GRANT EXECUTE ON dbo.sp_sysdac_ensure_dac_creator to PUBLIC
-- we allow anybody to execute the sprocs, they are guarded by the is_dac_creator function
GRANT EXECUTE ON dbo.sp_sysdac_rename_database to PUBLIC
GRANT EXECUTE ON dbo.sp_sysdac_drop_database to PUBLIC
GRANT EXECUTE ON dbo.sp_sysdac_update_instance to PUBLIC
GRANT EXECUTE ON dbo.sp_sysdac_upgrade_instance to PUBLIC
GRANT EXECUTE ON dbo.sp_sysdac_delete_instance to PUBLIC
GRANT EXECUTE ON dbo.sp_sysdac_delete_history to PUBLIC
GRANT EXECUTE ON dbo.sp_sysdac_add_instance to PUBLIC
GRANT EXECUTE ON dbo.sp_sysdac_add_history_entry to PUBLIC
GRANT EXECUTE ON dbo.sp_sysdac_update_history_entry to PUBLIC
--End DAC Script
RAISERROR('', 0, 1) WITH NOWAIT;
RAISERROR('------------------------------------', 0, 1) WITH NOWAIT;
RAISERROR('Execution of InstDac.SQL complete', 0, 1) WITH NOWAIT;
RAISERROR('------------------------------------', 0, 1) WITH NOWAIT;
GO
/**************************************************************/
/* END DAC SCRIPTS */
/**************************************************************//**************************************************************/
/* BEGIN UTILITY SCRIPTS */
/**************************************************************/
-- These settings are necessary for the Utility.
SET ANSI_NULLS ON
SET ANSI_NULL_DFLT_ON ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET NUMERIC_ROUNDABORT OFF
SET QUOTED_IDENTIFIER ON
GO
IF (OBJECT_ID ('tempdb..#configuration_original_values') IS NOT NULL)
BEGIN
DROP TABLE #configuration_original_values;
END;
GO
-- We call SQL Agent procs that require the Agent XPs config value to be enabled. Normally, Agent XPs is
-- only enabled when Agent is running, but there are cases (e.g. upgrade) where this script is executed but
-- Agent will never be running. Force the configuration setting on so that we can run even in these cases.
DECLARE @advanced_options_original_value INT;
DECLARE @configuration_original_value INT;
DECLARE @configuration_option VARCHAR(128) = 'Agent XPs';
EXEC #sp_enable_component
@comp_name = @configuration_option,
@advopt_old_value = @advanced_options_original_value OUTPUT,
@comp_old_value = @configuration_original_value OUTPUT;
-- Save the original value of the config options that we just changed. We'll restore the original values
-- when Utility DDL is done.
SELECT
@configuration_option AS configuration_option,
@advanced_options_original_value AS advanced_options_original_value,
@configuration_original_value AS configuration_original_value
INTO #configuration_original_values;
GO
-----------------------------------------------------------
-- Security for Utility objects
-----------------------------------------------------------
IF ( NOT EXISTS (SELECT * FROM sys.database_principals
WHERE name = N'UtilityCMRReader' AND type = 'R'))
BEGIN
CREATE ROLE [UtilityCMRReader]
END
ELSE -- if the role exists check to see if it has members
BEGIN
IF NOT EXISTS (SELECT rm.member_principal_id
FROM sys.database_principals dp
INNER JOIN sys.database_role_members rm ON rm.role_principal_id = dp.principal_id
WHERE name = N'UtilityCMRReader' AND type = 'R')
BEGIN
-- if the role has no members drop and recreate it
DROP ROLE [UtilityCMRReader]
CREATE ROLE [UtilityCMRReader]
END
END
GO
IF ( NOT EXISTS (SELECT * FROM sys.database_principals
WHERE name = N'UtilityIMRWriter' AND type = 'R'))
BEGIN
CREATE ROLE [UtilityIMRWriter]
END
ELSE -- if the role exists check to see if it has members
BEGIN
IF NOT EXISTS (SELECT rm.member_principal_id
FROM sys.database_principals dp
INNER JOIN sys.database_role_members rm ON rm.role_principal_id = dp.principal_id
WHERE name = N'UtilityIMRWriter' AND type = 'R')
BEGIN
-- if the role has no members drop and recreate it
DROP ROLE [UtilityIMRWriter]
CREATE ROLE [UtilityIMRWriter]
END
END
GO
IF ( NOT EXISTS (SELECT * FROM sys.database_principals
WHERE name = N'UtilityIMRReader' AND type = 'R'))
BEGIN
CREATE ROLE [UtilityIMRReader]
END
ELSE -- if the role exists check to see if it has members
BEGIN
IF NOT EXISTS (SELECT rm.member_principal_id
FROM sys.database_principals dp
INNER JOIN sys.database_role_members rm ON rm.role_principal_id = dp.principal_id
WHERE name = N'UtilityIMRReader' AND type = 'R')
BEGIN
-- if the role has no members drop and recreate it
DROP ROLE [UtilityIMRReader]
CREATE ROLE [UtilityIMRReader]
END
END
GO
-- A UtilityIMRWriter is also a UtilityIMRReader
EXECUTE sp_addrolemember @rolename = 'UtilityIMRReader' ,
@membername = 'UtilityIMRWriter'
GO
/**************************************************************************/
/* Create the Utility Control Point configuration table */
/* This table stores configuration values for the UCP. */
/**************************************************************************/
IF(OBJECT_ID(N'[dbo].[sysutility_ucp_configuration_internal]', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table [dbo].[sysutility_ucp_configuration_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_configuration_internal] (
name sysname PRIMARY KEY CLUSTERED NOT NULL,
current_value sql_variant NULL);
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'UtilityName', '');
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'MdwDatabaseName', '');
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'UtilityDescription', '');
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'UtilityDateCreated', '');
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'UtilityCreatedBy', '');
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'OverUtilizationTrailingWindow', 1);
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'OverUtilizationOccurenceFrequency', 25);
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'UnderUtilizationTrailingWindow', 168);
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'UnderUtilizationOccurenceFrequency', 90);
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'MdwRetentionLengthInDaysForMinutesHistory', 2);
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'MdwRetentionLengthInDaysForHoursHistory', 31);
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'MdwRetentionLengthInDaysForDaysHistory', 366);
INSERT INTO [dbo].[sysutility_ucp_configuration_internal] (name, current_value)
VALUES (N'UtilityVersion', N'1.0.0.0');
END
GO
/**********************************************************************/
/* Create the Utility Control Point configuration view */
/**********************************************************************/
IF(OBJECT_ID(N'[dbo].[sysutility_ucp_configuration]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_configuration]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_configuration]
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_configuration]...', 0, 1) WITH NOWAIT;
GO
CREATE VIEW [dbo].[sysutility_ucp_configuration]
AS
SELECT
name,
current_value
FROM [dbo].[sysutility_ucp_configuration_internal]
GO
/**********************************************************************/
/* Create the utility control point policy configuration view */
/* This view returns the occurrence frequency and trailing window for */
/* both over and under utilization resource health policy types */
/**********************************************************************/
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_policy_configuration]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_policy_configuration]', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_policy_configuration
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_policy_configuration]...', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_policy_configuration AS
(
SELECT 1 AS utilization_type
, CAST(UnderUtilizationOccurenceFrequency AS INT) AS occurence_frequency
, CAST(UnderUtilizationTrailingWindow AS INT) AS trailing_window
FROM (SELECT name, current_value FROM msdb.dbo.sysutility_ucp_configuration) config
PIVOT (MAX(current_value) FOR name IN (UnderUtilizationOccurenceFrequency, UnderUtilizationTrailingWindow)) pvt
UNION ALL
SELECT 2 AS utilization_type
, CAST(OverUtilizationOccurenceFrequency AS INT) AS occurence_frequency
, CAST(OverUtilizationTrailingWindow AS INT) AS trailing_window
FROM (SELECT name, current_value FROM msdb.dbo.sysutility_ucp_configuration) config
PIVOT (MAX(current_value) FOR name IN (OverUtilizationOccurenceFrequency, OverUtilizationTrailingWindow)) pvt
)
GO
/********************************************************************
Function fn_sysutility_get_is_instance_ucp
Description: Returns 1 if the local instance is a UCP, 0 otherwise
********************************************************************/
IF OBJECT_ID(N'[dbo].[fn_sysutility_get_is_instance_ucp]') IS NOT NULL
BEGIN
RAISERROR('Dropping [dbo].[fn_sysutility_get_is_instance_ucp]', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysutility_get_is_instance_ucp];
END
GO
RAISERROR('Creating [dbo].[fn_sysutility_get_is_instance_ucp]', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_get_is_instance_ucp]()
RETURNS BIT
AS
BEGIN
RETURN (
SELECT
CASE
WHEN ISNULL ((SELECT CAST (current_value as sysname) FROM msdb.dbo.sysutility_ucp_configuration_internal WHERE name = 'UtilityName'), '') = ''
THEN 0
ELSE 1
END)
END;
GO
/********************************************************************
Function fn_sysutility_get_culture_invariant_conversion_style_internal
Description: Returns an integer that can be passed to CONVERT's "style" parameter
in order to round-trip a value of the specified type to or from a string without
data loss and in a culture-invariant way.
********************************************************************/
IF OBJECT_ID('dbo.fn_sysutility_get_culture_invariant_conversion_style_internal') IS NOT NULL
BEGIN
DROP FUNCTION dbo.fn_sysutility_get_culture_invariant_conversion_style_internal;
END;
GO
CREATE FUNCTION dbo.fn_sysutility_get_culture_invariant_conversion_style_internal (@data_type varchar(30))
RETURNS tinyint
AS
BEGIN
RETURN
CASE
-- ISO8601, e.g. "yyyy-mm-ddThh:mi:ss.mmm"
WHEN @data_type IN ('datetime', 'datetimeoffset', 'smalldatetime', 'datetime2', 'date', 'time') THEN 126
-- scientific notation, 16 digits
WHEN @data_type IN ('real', 'float') THEN 2
-- e.g. "0x12AB"
WHEN @data_type IN ('binary', 'varbinary') THEN 1
-- all other types including bit, integer types, (n)varchar, decimal/numeric
ELSE 0
END;
END;
GO
/********************************************************************
Create "stub" objects that stand in for Utility MDW objects.
We have views in msdb that wrap tables, views, and functions in the MDW database. The
sysutility_mdw database is only created when an instance is made a UCP, so at the time of
instmsdb.sql execution sysutility_mdw doesn't yet exist. This is a problem because views
and inline functions in msdb cannot be created unless all of the objects (and columns)
that they reference do exist. The current solution is to create these "stub" objects in
msdb, create synonyms pointing to the stub objects, then reference the synonyms within any
functions or views in msdb that need to reference MDW tables. If the instance is made a
UCP, the Create UCP process executes the sp_sysutility_ucp_initialize_mdw stored proc,
which will redirect the synonyms to reference the true MDW tables after the sysutility_mdw
database has been created.
These stub objects should only be modified when the structure of one of the corresponding
MDW objects is modified. Note that these objects will never hold any data, so there is no
reason to bother with build-to-build schema upgrade steps; we can safely drop and recreate
them whenever instmsdb.sql is executed.
********************************************************************/
------ BEGIN UTILITY MDW STUB OBJECTS ------
-- Stub for MDW object [snapshots].[sysutility_ucp_core.latest_dacs]
IF OBJECT_ID(N'[dbo].[sysutility_ucp_dacs_stub]') IS NOT NULL
BEGIN
RAISERROR('Dropping table [dbo].[sysutility_ucp_dacs_stub]', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_ucp_dacs_stub];
END;
GO
RAISERROR('Creating table [sysutility_ucp_dacs_stub]', 0, 1) WITH NOWAIT;
CREATE TABLE [sysutility_ucp_dacs_stub]
(
[dac_id] INT IDENTITY, -- todo (VSTS #345036): This column will be removed
[physical_server_name] SYSNAME,
[server_instance_name] SYSNAME, -- the server-qualified instance name
[dac_name] SYSNAME,
[dac_deploy_date] DATETIME,
[dac_description] NVARCHAR(4000) NULL,
[urn] NVARCHAR(4000),
[powershell_path] NVARCHAR(4000),
[processing_time] DATETIMEOFFSET(7),
batch_time DATETIMEOFFSET(7),
-- todo (VSTS #345040) (no measure columns in dimension tables)
[dac_percent_total_cpu_utilization] REAL
)
GO
-- Stub for MDW object [snapshots].[sysutility_ucp_core.latest_volumes]
IF OBJECT_ID(N'[dbo].[sysutility_ucp_volumes_stub]') IS NOT NULL
BEGIN
RAISERROR('Dropping table [dbo].[sysutility_ucp_volumes_stub]', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_ucp_volumes_stub];
END;
GO
RAISERROR('Creating table [sysutility_ucp_latest_volumes_stub]', 0, 1) WITH NOWAIT;
CREATE TABLE [sysutility_ucp_volumes_stub]
(
[ID] INT IDENTITY, -- todo (VSTS #345036): This column will be removed
virtual_server_name SYSNAME,
physical_server_name SYSNAME,
volume_device_id SYSNAME,
volume_name SYSNAME,
-- todo (VSTS #345040) (no measure columns in dimension tables)
total_space_available real,
free_space real,
total_space_utilized real,
percent_total_space_utilization real,
processing_time DATETIMEOFFSET(7),
batch_time DATETIMEOFFSET(7),
powershell_path NVARCHAR(4000)
)
-- Stub for MDW object [snapshots].[sysutility_ucp_core.latest_computers]
IF OBJECT_ID(N'[dbo].[sysutility_ucp_computers_stub]') IS NOT NULL
BEGIN
RAISERROR('Dropping table [dbo].[sysutility_ucp_computers_stub]', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_ucp_computers_stub];
END;
GO
RAISERROR('Creating table [sysutility_ucp_computers_stub]', 0, 1) WITH NOWAIT;
CREATE TABLE [sysutility_ucp_computers_stub]
(
[id] INT IDENTITY, -- todo (VSTS #345036): This column will be removed
virtual_server_name SYSNAME,
physical_server_name SYSNAME, -- differs from server_name for clustered servers
is_clustered_server INT,
num_processors INT,
cpu_name NVARCHAR(128),
cpu_caption NVARCHAR(128),
cpu_family NVARCHAR(128),
cpu_architecture NVARCHAR(64),
cpu_max_clock_speed DECIMAL(10),
cpu_clock_speed DECIMAL(10),
l2_cache_size DECIMAL(10),
l3_cache_size DECIMAL(10),
urn NVARCHAR(4000),
powershell_path NVARCHAR(4000),
processing_time DATETIMEOFFSET(7),
batch_time DATETIMEOFFSET(7),
percent_total_cpu_utilization REAL -- todo (VSTS #345040) (no measure columns in dimension tables)
)
-- Stub for MDW object [snapshots].[sysutility_ucp_latest_smo_servers]
IF OBJECT_ID(N'[dbo].[sysutility_ucp_smo_servers_stub]') IS NOT NULL
BEGIN
RAISERROR('Dropping table [dbo].[sysutility_ucp_smo_servers_stub]', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_ucp_smo_servers_stub];
END;
GO
RAISERROR ('Creating table [dbo].[sysutility_ucp_smo_servers_stub]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_smo_servers_stub]
(
[urn] NVARCHAR(512),
[powershell_path] NVARCHAR(4000),
[processing_time] DATETIMEOFFSET(7),
[batch_time] DATETIMEOFFSET(7),
[AuditLevel] SMALLINT,
[BackupDirectory] NVARCHAR(260),
[BrowserServiceAccount] NVARCHAR(128),
[BrowserStartMode] SMALLINT,
[BuildClrVersionString] NVARCHAR(20),
[BuildNumber] INT,
[Collation] NVARCHAR(128),
[CollationID] INT,
[ComparisonStyle] INT,
[ComputerNamePhysicalNetBIOS] NVARCHAR(128),
[DefaultFile] NVARCHAR(260),
[DefaultLog] NVARCHAR(260),
[Edition] NVARCHAR(64),
[EngineEdition] SMALLINT,
[ErrorLogPath] NVARCHAR(260),
[FilestreamShareName] NVARCHAR(260),
[InstallDataDirectory] NVARCHAR(260),
[InstallSharedDirectory] NVARCHAR(260),
[InstanceName] NVARCHAR(128),
[IsCaseSensitive] BIT,
[IsClustered] BIT,
[IsFullTextInstalled] BIT,
[IsSingleUser] BIT,
[Language] NVARCHAR(64),
[MailProfile] NVARCHAR(128),
[MasterDBLogPath] NVARCHAR(260),
[MasterDBPath] NVARCHAR(260),
[MaxPrecision] TINYINT,
[Name] NVARCHAR(128),
[NamedPipesEnabled] BIT,
[NetName] NVARCHAR(128),
[NumberOfLogFiles] INT,
[OSVersion] NVARCHAR(32),
[PerfMonMode] SMALLINT,
[PhysicalMemory] INT,
[Platform] NVARCHAR(32),
[Processors] SMALLINT,
[ProcessorUsage] INT,
[Product] NVARCHAR(48),
[ProductLevel] NVARCHAR(32),
[ResourceVersionString] NVARCHAR(32),
[RootDirectory] NVARCHAR(260),
[ServerType] SMALLINT,
[ServiceAccount] NVARCHAR(128),
[ServiceInstanceId] NVARCHAR(64),
[ServiceName] NVARCHAR(64),
[ServiceStartMode] SMALLINT,
[SqlCharSet] SMALLINT,
[SqlCharSetName] NVARCHAR(32),
[SqlDomainGroup] NVARCHAR(260),
[SqlSortOrder] SMALLINT,
[SqlSortOrderName] NVARCHAR(64),
[Status] SMALLINT,
[TapeLoadWaitTime] INT,
[TcpEnabled] BIT,
[VersionMajor] INT,
[VersionMinor] INT,
[VersionString] NVARCHAR(32)
);
GO
-- Stub for MDW object [snapshots].[sysutility_ucp_databases]
IF OBJECT_ID(N'[dbo].[sysutility_ucp_databases_stub]') IS NOT NULL
BEGIN
RAISERROR('Dropping table [dbo].[sysutility_ucp_databases_stub]', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_ucp_databases_stub];
END;
GO
RAISERROR ('Creating table [dbo].[sysutility_ucp_databases_stub]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_databases_stub]
(
[urn] NVARCHAR(512)
, [powershell_path] NVARCHAR(MAX)
, [processing_time] DATETIMEOFFSET(7)
, [batch_time] DATETIMEOFFSET(7)
, [server_instance_name] SYSNAME
, [parent_urn] NVARCHAR(320)
, [Collation] NVARCHAR(128)
, [CompatibilityLevel] SMALLINT
, [CreateDate] DATETIME
, [EncryptionEnabled] BIT
, [Name] NVARCHAR(128)
, [RecoveryModel] SMALLINT
, [Trustworthy] BIT
, [state] TINYINT
);
GO
-- Stub for MDW object [snapshots].[sysutility_ucp_filegroups]
IF OBJECT_ID(N'[dbo].[sysutility_ucp_filegroups_stub]') IS NOT NULL
BEGIN
RAISERROR('Dropping table [dbo].[sysutility_ucp_filegroups_stub]', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_ucp_filegroups_stub];
END;
GO
RAISERROR ('Creating table [dbo].[sysutility_ucp_filegroups_stub]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_filegroups_stub]
(
[urn] NVARCHAR(780)
, [powershell_path] NVARCHAR(MAX)
, [processing_time] DATETIMEOFFSET(7)
, [batch_time] DATETIMEOFFSET(7)
, [server_instance_name] SYSNAME
, [database_name] SYSNAME
, [parent_urn] NVARCHAR(512)
, [Name] NVARCHAR(128)
);
GO
-- Stub for MDW object [snapshots].[sysutility_ucp_datafiles]
IF OBJECT_ID(N'[dbo].[sysutility_ucp_datafiles_stub]') IS NOT NULL
BEGIN
RAISERROR('Dropping table [dbo].[sysutility_ucp_datafiles_stub]', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_ucp_datafiles_stub];
END;
GO
RAISERROR ('Creating table [dbo].[sysutility_ucp_datafiles_stub]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_datafiles_stub]
(
[urn] NVARCHAR(1500)
, [powershell_path] NVARCHAR(MAX)
, [processing_time] DATETIMEOFFSET(7)
, [batch_time] DATETIMEOFFSET(7)
, [server_instance_name] SYSNAME
, [database_name] SYSNAME
, [filegroup_name] SYSNAME
, [parent_urn] NVARCHAR(780)
, [physical_server_name] SYSNAME
, [volume_name] SYSNAME
, [volume_device_id] SYSNAME
, [Growth] REAL
, [GrowthType] SMALLINT
, [MaxSize] REAL
, [Name] NVARCHAR(128)
, [Size] REAL
, [UsedSpace] REAL
, [FileName] NVARCHAR(260)
, [VolumeFreeSpace] BIGINT
, [available_space] REAL
);
GO
-- Stub for MDW object [snapshots].[sysutility_ucp_logfiles]
IF OBJECT_ID(N'[dbo].[sysutility_ucp_logfiles_stub]') IS NOT NULL
BEGIN
RAISERROR('Dropping table [dbo].[sysutility_ucp_logfiles_stub]', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_ucp_logfiles_stub];
END;
GO
RAISERROR ('Creating table [dbo].[sysutility_ucp_logfiles_stub]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_logfiles_stub]
(
[urn] NVARCHAR(1500)
, [powershell_path] NVARCHAR(MAX)
, [processing_time] DATETIMEOFFSET(7)
, [batch_time] DATETIMEOFFSET(7)
, [server_instance_name] SYSNAME
, [database_name] SYSNAME
, [parent_urn] NVARCHAR(780)
, [physical_server_name] SYSNAME
, [volume_name] SYSNAME
, [volume_device_id] SYSNAME
, [Growth] REAL
, [GrowthType] SMALLINT
, [MaxSize] REAL
, [Name] NVARCHAR(128)
, [Size] REAL
, [UsedSpace] REAL
, [FileName] NVARCHAR(260)
, [VolumeFreeSpace] BIGINT
, [available_space] REAL
)
GO
-- Stub for MDW object [snapshots].[sysutility_ucp_cpu_utilization]
IF OBJECT_ID(N'[dbo].[sysutility_ucp_cpu_utilization_stub]') IS NOT NULL
BEGIN
RAISERROR('Dropping table [dbo].[sysutility_ucp_cpu_utilization_stub]', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_ucp_cpu_utilization_stub];
END;
GO
RAISERROR ('Creating table [dbo].[sysutility_ucp_cpu_utilization_stub]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_cpu_utilization_stub]
(
[processing_time] DATETIMEOFFSET(7),
[aggregation_type] TINYINT NOT NULL,
[object_type] TINYINT NOT NULL,
-- Dimension keys
[physical_server_name] SYSNAME DEFAULT '',
[server_instance_name] SYSNAME DEFAULT '',
[database_name] SYSNAME DEFAULT '',
-- The actual measure columns.
percent_total_cpu_utilization REAL
)
GO
-- Stub for MDW object [snapshots].[sysutility_ucp_logfiles]
IF OBJECT_ID(N'[dbo].[sysutility_ucp_space_utilization_stub]') IS NOT NULL
BEGIN
RAISERROR('Dropping table [dbo].[sysutility_ucp_space_utilization_stub]', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_ucp_space_utilization_stub];
END;
GO
RAISERROR ('Creating table [dbo].[sysutility_ucp_space_utilization_stub]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_space_utilization_stub]
(
[processing_time] DATETIMEOFFSET(7) NOT NULL,
[aggregation_type] TINYINT NOT NULL,
[object_type] TINYINT NOT NULL,
-- The dimension columns
[virtual_server_name] SYSNAME DEFAULT '',
[server_instance_name] SYSNAME DEFAULT '',
[volume_device_id] SYSNAME DEFAULT '',
[database_name] SYSNAME DEFAULT '',
[filegroup_name] SYSNAME DEFAULT '',
[dbfile_name] SYSNAME DEFAULT '',
[used_space_bytes] REAL,
[allocated_space_bytes] REAL,
[total_space_bytes] REAL,
[available_space_bytes] REAL
)
GO
------ END UTILITY MDW STUB OBJECTS ------
/********************************************************************
Procedure [sp_sysutility_ucp_recreate_synonym_internal]
Description: Helper proc to create/recreate a synonym
********************************************************************/
IF OBJECT_ID(N'[dbo].[sp_sysutility_ucp_recreate_synonym_internal]') IS NOT NULL
BEGIN
RAISERROR('Dropping [dbo].[sp_sysutility_ucp_recreate_synonym_internal] procedure', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_ucp_recreate_synonym_internal];
END
GO
RAISERROR('Creating [dbo].[sp_sysutility_ucp_recreate_synonym_internal] procedure', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_recreate_synonym_internal]
@synonym_name sysname, @database_name sysname, @schema_name sysname, @object_name sysname
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE @null_column nvarchar(100)
SET @null_column = NULL
IF (@synonym_name IS NULL OR @synonym_name = N'')
SET @null_column = '@synonym_name'
ELSE IF (@object_name IS NULL OR @object_name = N'')
SET @null_column = '@object_name'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_ucp_recreate_synonym')
RETURN(1)
END
IF EXISTS (SELECT name FROM sys.objects WHERE object_id = OBJECT_ID(@synonym_name) )
BEGIN
DECLARE @drop_statement nvarchar(600)
SET @drop_statement = N'DROP SYNONYM [dbo].' + QUOTENAME(@synonym_name)
RAISERROR ('Executing: %s', 0, 1, @drop_statement) WITH NOWAIT;
EXEC sp_executesql @drop_statement
END
DECLARE @full_object_name nvarchar(776) = QUOTENAME(@database_name) + '.' + QUOTENAME(@schema_name) + '.' + QUOTENAME(@object_name)
DECLARE @create_statement nvarchar(1060)
SET @create_statement = N'CREATE SYNONYM [dbo].' + QUOTENAME(@synonym_name) + ' FOR ' + @full_object_name
RAISERROR ('Executing: %s', 0, 1, @create_statement) WITH NOWAIT;
EXEC sp_executesql @create_statement
END
GO
/********************************************************************
Procedure [sp_sysutility_ucp_initialize_mdw]
Description: This procedure will create the Utility synonyms. This proc is called
by the Utility OM as part of the Create UCP process. It is also called whenever
instmsdb.sql is executed. If the instance is a UCP and if sysutility_mdw exists, the
synonyms will be created to reference objects in the Utility MDW database.
Otherwise, the synonyms will reference stub objects in msdb. This allows the
Utility msdb objects to be created even when sysutility_mdw does not exist.
Note that this proc requires the 'Agent XPs' sp_configure setting to be enabled.
During upgrade, this setting will need to be manually enabled, since upgrade scripts
are executed while Agent is stopped.
Parameters:
@mdw_database_name - Name of the Utility MDW database ('sysutility_mdw')
@require_mdw - If set to 1, the sysutility_mdw database must exist or an error is
thrown. When this procedure is executed within instmsdb.sql, the param is set
to 0 so that it tolerates a missing MDW db. When the procedure is executed by
the Utility OM, this parameter is not passed (and defaults to 1), so the MDW
database must exist.
@force_stub_use - If set to 1 (default is 0), the msdb wrapper views will always be
redirected to the msdb stub tables, even if the instance is a UCP. This is set to
1 when the proc is run by instmsdb.sql, to solve an upgrade issue: setup upgrades
the msdb schema before upgrading MDW schema. The new msdb view definitions could
reference new columns that have not yet been added to the MDW tables (because MDW
has not yet been upgraded by setup). Setting @force_stub_use to 1 allows
instmsdb.sql to update the msdb wrapper views before MDW has been upgraded. The
procedure will be executed again after instmdw.sql runs (in
post_upgrade_ucp_cmdw.sql), and that execution will redirect the synonyms to
MDW, if the instance is a UCP.
@refresh_views - If set to 1 (default) the msdb wrapper views will be updated so
that view metadata reflects any changes to the schema of referenced tables.
@refresh_views is always set to 0 when this proc is executed by instmsdb.sql.
This is because the final execution of the proc in instmsdb.sql may have pointed
the (upgraded) msdb wrapper views to MDW tables that have not yet been upgraded,
and may lack columns that are referenced by the msdb wrapper views. If the
instance is a UCP, the views will be refreshed when the proc is run following
MDW upgrade.
********************************************************************/
IF OBJECT_ID ('[dbo].[sp_sysutility_ucp_initialize_mdw]') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_ucp_initialize_mdw]', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_ucp_initialize_mdw]
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_ucp_initialize_mdw]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_initialize_mdw]
@mdw_database_name SYSNAME,
@require_mdw BIT = 1,
@force_stub_use BIT = 0,
@refresh_views BIT = 1
WITH EXECUTE AS OWNER
AS
BEGIN
-- Check if @mdw_database_name is NULL or empty
IF (@mdw_database_name IS NULL OR @mdw_database_name = N'')
BEGIN
RAISERROR(14043, -1, -1, 'mdw_database_name', 'sp_sysutility_ucp_initialize_mdw')
RETURN(1)
END
IF (@require_mdw = 1) AND NOT EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE name = @mdw_database_name)
BEGIN
RAISERROR(37002, -1, -1, @mdw_database_name)
RETURN(1)
END
DECLARE @database sysname;
DECLARE @schema sysname;
DECLARE @is_ucp bit;
-- If the sysutility_mdw database has been installed and the instance appears to be a UCP, we should
-- point the synonyms at the MDW objects. Otherwise, the synonyms should reference the stub objects
-- (with a "_stub" suffix) that we just created. Note that during UCP creation, this proc is called
-- at an interim step before fn_sysutility_get_is_instance_ucp returns 1. However, @require_mdw will
-- be set to 1 in this case, telling us that we should redirect the synonyms to the MDW db even though .
-- the instance is not (yet) completely set up as a UCP.
IF (DB_ID (@mdw_database_name) IS NOT NULL)
AND ((@require_mdw = 1) OR (dbo.fn_sysutility_get_is_instance_ucp() = 1))
AND (@force_stub_use = 0)
BEGIN
-- This instance is a UCP; synonyms should reference objects in sysutility_mdw
SET @database = @mdw_database_name;
SET @schema = 'sysutility_ucp_core';
-- Dimensions
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_computers', @database, @schema, 'latest_computers';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_volumes', @database, @schema, 'latest_volumes';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_dacs', @database, @schema, 'latest_dacs';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_smo_servers', @database, @schema, 'latest_smo_servers';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_databases', @database, @schema, 'latest_databases';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_filegroups', @database, @schema, 'latest_filegroups';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_datafiles', @database, @schema, 'latest_datafiles';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_logfiles', @database, @schema, 'latest_logfiles';
-- Measures
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_cpu_utilization', @database, @schema, 'cpu_utilization';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_space_utilization', @database, @schema, 'space_utilization';
-- Now that msdb is set up, call a setup proc in MDW to do any runtime initialization that is
-- needed in that database. Only exec the proc if it exists -- it won't exist yet when instmsdb.sql
-- is run on upgrade from CTP3 to RTM, because the MDW initialization proc was added post-CTP3 and
-- upgrade executes instmsdb.sql prior to instmdw.sql. This proc will be re-executed by the post-upgrade
-- script post_upgrade_ucp_cmdw.sql, and at that time the MDW proc will have been created.
DECLARE @sql nvarchar(max);
DECLARE @mdw_proc_name nvarchar(max);
SET @mdw_proc_name = QUOTENAME(@mdw_database_name) + '.sysutility_ucp_core.sp_initialize_mdw_internal';
SET @sql = 'EXEC ' + @mdw_proc_name;
IF OBJECT_ID (@mdw_proc_name) IS NOT NULL
BEGIN
RAISERROR ('Executing %s', 0, 1, @mdw_proc_name) WITH NOWAIT;
EXEC (@sql);
END
ELSE BEGIN
RAISERROR ('Skipping execution of %s', 0, 1, @mdw_proc_name) WITH NOWAIT;
END;
END
ELSE BEGIN
-- This instance is not a UCP; synonyms should reference msdb stub objects
SET @database = 'msdb';
SET @schema = 'dbo';
-- Dimensions
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_computers', @database, @schema, 'sysutility_ucp_computers_stub';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_volumes', @database, @schema, 'sysutility_ucp_volumes_stub';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_dacs', @database, @schema, 'sysutility_ucp_dacs_stub';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_smo_servers', @database, @schema, 'sysutility_ucp_smo_servers_stub';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_databases', @database, @schema, 'sysutility_ucp_databases_stub';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_filegroups', @database, @schema, 'sysutility_ucp_filegroups_stub';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_datafiles', @database, @schema, 'sysutility_ucp_datafiles_stub';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_logfiles', @database, @schema, 'sysutility_ucp_logfiles_stub';
-- Measures
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_cpu_utilization', @database, @schema, 'sysutility_ucp_cpu_utilization_stub';
EXEC dbo.sp_sysutility_ucp_recreate_synonym_internal N'syn_sysutility_ucp_space_utilization', @database, @schema, 'sysutility_ucp_space_utilization_stub';
END;
IF (@refresh_views = 1)
BEGIN
-- Refresh the msdb wrapper views to ensure that the view metadata matches the underlying table metadata.
-- This is necessary for two reasons:
-- a) When this procecure is executed by the Create UCP process, it may change the structure of the tables
-- that the msdb wrapper views reference, by redirecting the synonyms from the msdb stub tables to
-- different tables in MDW. The refresh ensures that the view metadata matches that of the new
-- referenced tables.
-- b) The proc is also executed after msdb and MDW schema upgrade. In this case, the MDW upgrade may have
-- changed the MDW table schema even if the synonyms weren't redirected.
RAISERROR ('Refreshing msdb wrapper views', 0, 1) WITH NOWAIT;
EXEC dbo.sp_refreshview N'dbo.sysutility_ucp_computers';
EXEC dbo.sp_refreshview N'dbo.sysutility_ucp_volumes';
EXEC dbo.sp_refreshview N'dbo.sysutility_ucp_instances';
EXEC dbo.sp_refreshview N'dbo.sysutility_ucp_databases';
EXEC dbo.sp_refreshview N'dbo.sysutility_ucp_filegroups';
EXEC dbo.sp_refreshview N'dbo.sysutility_ucp_datafiles';
EXEC dbo.sp_refreshview N'dbo.sysutility_ucp_logfiles';
EXEC dbo.sp_refreshview N'dbo.sysutility_ucp_utility_space_utilization';
END;
END;
GO
-- Create the Utility synonyms. For details, see comments prior to "BEGIN UTILITY MDW STUB OBJECTS",
-- above. We need to create the synonyms at this point so that we can create the Utility msdb wrapper
-- views that reference the synonyms. This execution uses @force_stub_use=1 and @refresh_views=0; see
-- the documentation for these parameters in the proc header.
EXEC msdb.dbo.sp_sysutility_ucp_initialize_mdw
@mdw_database_name = 'sysutility_mdw',
@require_mdw = 0,
@force_stub_use = 1,
@refresh_views = 0;
GO
---------------------------------------------------------------------
-- SP to setup the managed instance proxy for a network account
---------------------------------------------------------------------
IF OBJECT_ID ('dbo.sp_sysutility_mi_configure_proxy_account') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_mi_configure_proxy_account]', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_configure_proxy_account]
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_mi_configure_proxy_account]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_configure_proxy_account]
@proxy_name sysname,
@credential_name sysname,
@network_account sysname,
@password sysname
AS
BEGIN
DECLARE @retval INT
DECLARE @null_column sysname
DECLARE @expression NVARCHAR(MAX) = N''
DECLARE @network_account_sid varbinary(85)
SET @null_column = NULL
IF (@proxy_name IS NULL OR @proxy_name = N'')
SET @null_column = '@proxy_name'
ELSE IF (@credential_name IS NULL OR @credential_name = N'')
SET @null_column = '@credential_name'
ELSE IF (@network_account IS NULL OR @network_account = N'')
SET @null_column = '@network_account'
ELSE IF (@password IS NULL OR @password = N'')
SET @null_column = '@password'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_mi_configure_proxy_account')
RETURN(1)
END
SET @network_account_sid = SUSER_SID(@network_account, 0) -- case insensensitive lookup
SET @network_account = SUSER_SNAME(@network_account_sid) -- get the caseing of the user that the server recognizes
IF NOT EXISTS (SELECT sid FROM msdb.sys.syslogins WHERE sid = @network_account_sid)
BEGIN
SET @expression = N'CREATE LOGIN '+ QUOTENAME(@network_account) +' FROM WINDOWS;'
EXEC sp_executesql @expression
END
DECLARE @create_credential nvarchar(4000)
DECLARE @print_credential nvarchar(4000)
IF EXISTS(SELECT * FROM master.sys.credentials WHERE name = @credential_name)
BEGIN
set @create_credential = 'DROP CREDENTIAL ' + QUOTENAME(@credential_name)
RAISERROR (@create_credential, 0, 1) WITH NOWAIT;
EXEC sp_executesql @create_credential
END
set @create_credential = 'CREATE CREDENTIAL ' + QUOTENAME(@credential_name) + ' WITH IDENTITY=N' + QUOTENAME(@network_account, '''') + ', SECRET=N' + QUOTENAME(@password, '''')
set @print_credential = 'CREATE CREDENTIAL ' + QUOTENAME(@credential_name) + ' WITH IDENTITY=N' + QUOTENAME(@network_account, '''')
RAISERROR (@print_credential, 0, 1) WITH NOWAIT;
EXEC sp_executesql @create_credential
IF EXISTS(SELECT * FROM dbo.sysproxies WHERE (name = @proxy_name))
BEGIN
EXEC dbo.sp_delete_proxy @proxy_name=@proxy_name
END
EXEC dbo.sp_add_proxy @proxy_name=@proxy_name, @credential_name=@credential_name, @enabled=1
EXEC dbo.sp_grant_login_to_proxy @msdb_role=N'dc_admin', @proxy_name=@proxy_name
-- Grant the cmdexec subsystem to the proxy. This is the subsystem that DC uses to perform upload.
EXEC dbo.sp_grant_proxy_to_subsystem @proxy_name=@proxy_name, @subsystem_id=3
-- Allow the account to see the table schemas. This is because DC checks to make sure the mdw
-- schema matches the schema on the client.
-- One cannot grant privledges to oneself.
-- Since the caller is creating users by virtue of this sproc, it already can view server state
-- So, only grant veiw server state if the network_account is not the caller
IF( SUSER_SID() <> @network_account_sid )
BEGIN
-- GRANT VIEW SERVER STATE requires the expression to be executed in master.
SET @expression = N'use master; GRANT VIEW SERVER STATE TO ' + QUOTENAME(@network_account)
RAISERROR (@expression, 0, 1) WITH NOWAIT;
EXEC sp_executesql @expression
END
-- Add a user to the msdb database so that the proxy can be associated with the appropriate roles.
-- The user might already be associated with a user in msdb. If so, find that user name so that
-- roles can be assigned to it.
DECLARE @user_name SYSNAME = (SELECT name FROM msdb.sys.database_principals WHERE sid = @network_account_sid)
-- The "special principles" are not allowed to have roles added to them.
-- The database Users in the "special" category are dbo, sys, and INFORMATION_SCHEMA.
-- dbo is the only one that can have logins associated with it.
-- The following only checks dbo because the network_account has an associated login.
-- The else case (the user is msdb dbo), then they are effectively sysadmin in msdb and have
-- the required permissions for the proxy, and there is not need to grant roles anyway.
IF ((@user_name IS NULL) OR (@user_name <> N'dbo'))
BEGIN
-- This login doesn't have a user associated with it.
-- Go ahead and create a user for it in msdb
IF( @user_name IS NULL )
BEGIN
SET @user_name = @network_account
SET @expression = N'CREATE USER ' + QUOTENAME(@user_name)
EXEC sp_executesql @expression
END;
-- Allow the user to view the msdb database metadata. This allows DC (and ssis) to verify
-- the proxy's privledges.
-- One cannot grant privledges to oneself.
IF( SUSER_SID() <> @network_account_sid )
BEGIN
SET @expression = N'GRANT VIEW DEFINITION TO ' + QUOTENAME(@network_account)
RAISERROR (@expression, 0, 1) WITH NOWAIT;
EXEC sp_executesql @expression
END
-- Adding roles is idempotent, so go ahead and add them.
-- This role necessary for the proxy
EXEC sp_addrolemember @rolename=N'dc_proxy', @membername=@user_name
-- It needs to read the Utility tables. It requires execute permissions on the dac performance sp, so writer role is required.
EXEC sp_addrolemember @rolename=N'UtilityIMRWriter', @membername=@user_name
END
END
GO
---------------------------------------------------------------------
-- SP to provision the proxy for a network account on the CMR
---------------------------------------------------------------------
IF OBJECT_ID ('dbo.sp_sysutility_ucp_provision_proxy_account') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_ucp_provision_proxy_account]', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_ucp_provision_proxy_account]
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_ucp_provision_proxy_account]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_provision_proxy_account]
@network_account sysname,
@mdw_database_name sysname
AS
BEGIN
DECLARE @retval INT
DECLARE @null_column sysname
DECLARE @expression NVARCHAR(MAX) = N''
DECLARE @network_account_sid varbinary(85)
SET @null_column = NULL
IF (@network_account IS NULL OR @network_account = N'')
SET @null_column = '@network_account'
ELSE IF (@mdw_database_name IS NULL OR @mdw_database_name = N'')
SET @null_column = '@mdw_database_name'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_ucp_provision_proxy_account')
RETURN(1)
END
IF NOT EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE name = @mdw_database_name)
BEGIN
RAISERROR(37002, -1, -1, @mdw_database_name)
RETURN(1)
END
SET @network_account_sid = SUSER_SID(@network_account, 0) -- case insensensitive lookup
SET @network_account = SUSER_SNAME(@network_account_sid) -- get the caseing of the user that the server recognizes
IF NOT EXISTS (SELECT sid FROM msdb.sys.syslogins WHERE sid = @network_account_sid)
BEGIN
SET @expression = N'USE msdb; CREATE LOGIN '+ QUOTENAME(@network_account) + ' FROM WINDOWS;'
EXEC sp_executesql @expression
END
DECLARE @is_sysadmin INT
SELECT @is_sysadmin = 0
EXECUTE msdb.dbo.sp_sqlagent_has_server_access @login_name = @network_account, @is_sysadmin_member = @is_sysadmin OUTPUT
IF (@is_sysadmin = 0)
BEGIN
DECLARE @print_expression nvarchar(500)
SET @print_expression = @network_account + ' is NOT a SQL sysadmin'
RAISERROR (@print_expression, 0, 1) WITH NOWAIT;
IF NOT EXISTS(SELECT * FROM msdb.sys.database_principals WHERE sid = @network_account_sid)
BEGIN
SET @expression = N'USE msdb; CREATE USER ' + QUOTENAME(@network_account) +';'
EXEC sp_executesql @expression
END;
EXEC msdb.dbo.sp_addrolemember @rolename='dc_proxy', @membername=@network_account
DECLARE @grant_expression nvarchar(4000)
IF NOT EXISTS
(SELECT name from master.sys.databases
WHERE @network_account_sid = owner_sid
AND database_id = DB_ID(@mdw_database_name))
BEGIN
set @grant_expression =
'IF NOT EXISTS(SELECT * FROM ' + QUOTENAME(@mdw_database_name) +'.[sys].[database_principals] WHERE sid = SUSER_SID(' + QUOTENAME(@network_account, '''') +', 0))
BEGIN
RAISERROR (''Creating user ' + QUOTENAME(@network_account) + ' in ' + QUOTENAME(@mdw_database_name) + ''', 0, 1) WITH NOWAIT;
USE ' + QUOTENAME(@mdw_database_name) + '; CREATE USER ' + QUOTENAME(@network_account) + ';
END;
RAISERROR (''Add to UtilityMDWWriter role'', 0, 1) WITH NOWAIT;
EXEC ' + QUOTENAME(@mdw_database_name) + '.[dbo].[sp_addrolemember] @rolename=''UtilityMDWWriter'', @membername=' + QUOTENAME(@network_account) + ';'
RAISERROR (@grant_expression, 0, 1) WITH NOWAIT;
EXEC sp_executesql @grant_expression
END
END
END
GO
----------------------------------------------------------------------
-- SP to create the proxy account validator job
----------------------------------------------------------------------
IF OBJECT_ID ('dbo.sp_sysutility_mi_validate_proxy_account') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_mi_validate_proxy_account]', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_validate_proxy_account]
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_mi_validate_proxy_account]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_validate_proxy_account]
@proxy_name sysname,
@credential_name sysname,
@network_account sysname,
@password sysname
AS
BEGIN
DECLARE @retval INT
DECLARE @null_column sysname
SET @null_column = NULL
IF (@proxy_name IS NULL OR @proxy_name = N'')
SET @null_column = '@proxy_name'
ELSE IF (@credential_name IS NULL OR @credential_name = N'')
SET @null_column = '@credential_name'
ELSE IF (@network_account IS NULL OR @network_account = N'')
SET @null_column = '@network_account'
ELSE IF (@password IS NULL OR @password = N'')
SET @null_column = '@password'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_mi_validate_proxy_account')
RETURN(1)
END
DECLARE @instance_name nvarchar(128)
SET @instance_name = ISNULL(CONVERT(nvarchar(128), SERVERPROPERTY('InstanceName')), N'MSSQLSERVER')
DECLARE @job_name sysname
DECLARE @job_id uniqueidentifier
DECLARE @description nvarchar(512)
-- Delete the job if it already exists
SET @job_name = N'sysutility_check_proxy_credentials'
WHILE (EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @job_name))
BEGIN
EXEC sp_delete_job @job_name=@job_name
END
DECLARE @credential_statement nvarchar(4000)
DECLARE @print_credential nvarchar(4000)
IF EXISTS(select * from master.sys.credentials where name = @credential_name)
BEGIN
set @credential_statement = 'DROP CREDENTIAL ' + QUOTENAME(@credential_name)
RAISERROR (@credential_statement, 0, 1) WITH NOWAIT;
EXEC sp_executesql @credential_statement
END
set @credential_statement = 'CREATE CREDENTIAL ' + QUOTENAME(@credential_name) + ' WITH IDENTITY=N' + QUOTENAME(@network_account, '''') + ', SECRET=N' + QUOTENAME(@password, '''')
set @print_credential = 'CREATE CREDENTIAL ' + QUOTENAME(@credential_name) + ' WITH IDENTITY=N' + QUOTENAME(@network_account, '''')
RAISERROR (@print_credential, 0, 1) WITH NOWAIT;
EXEC sp_executesql @credential_statement
IF EXISTS(SELECT * FROM dbo.sysproxies WHERE (name = @proxy_name))
BEGIN
EXEC dbo.sp_delete_proxy @proxy_name=@proxy_name
END
-- Create the proxy and grant it to the cmdExec subsytem
EXEC dbo.sp_add_proxy @proxy_name=@proxy_name, @credential_name=@credential_name, @enabled=1
EXEC dbo.sp_grant_proxy_to_subsystem @proxy_name=@proxy_name, @subsystem_id=3
-- Create the job
EXEC msdb.dbo.sp_add_job @job_name=@job_name,
@enabled=1,
@notify_level_eventlog=0,
@notify_level_email=2,
@notify_level_netsend=2,
@notify_level_page=2,
@delete_level=0,
@category_id=0,
@job_id = @job_id OUTPUT
DECLARE @server_name SYSNAME = CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))
EXEC msdb.dbo.sp_add_jobserver @job_name=@job_name, @server_name = @server_name
DECLARE @collection_step_command nvarchar(512)
SET @collection_step_command = N'time /T'
EXEC msdb.dbo.sp_add_jobstep
@job_id=@job_id,
@step_name=N'Validate proxy account',
@step_id=1,
@cmdexec_success_code=0,
@on_fail_action=2,
@on_fail_step_id=0,
@on_success_action=1,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'CMDEXEC',
@command=@collection_step_command,
@proxy_name=@proxy_name,
@flags=16
END
GO
----------------------------------------------------------------------
-- A function that returns a powershell script which is used for
-- ensuring that the WMI queries necessary for data collection in the
-- Utility work correctly. The function is used for validation of the
-- Managed Instance and is run within a job step. It is exposed as a
-- to ease testing and troublshooting.
----------------------------------------------------------------------
IF (OBJECT_ID(N'[dbo].[fn_sysutility_mi_get_validate_wmi_script]') IS NOT NULL)
BEGIN
RAISERROR('Dropping [dbo].[fn_sysutility_mi_get_validate_wmi_script] function', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysutility_mi_get_validate_wmi_script];
END
GO
RAISERROR('Creating [dbo].[fn_sysutility_mi_get_validate_wmi_script] function', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_mi_get_validate_wmi_script]()
RETURNS NVARCHAR(MAX)
AS
BEGIN
RETURN
'# This script verifies that the following WMI objects are queriable
$objectsToValidate = "Win32_MountPoint",
"Win32_PerfRawData_PerfProc_Process",
"Win32_PerfRawData_PerfOS_Processor",
"Win32_Processor",
"Win32_Volume",
"Win32_LogicalDisk"
# The errorHappend variable keeps track of whether any class failed the check
$errorHappened=$false
# The SQL Agent Powershell subsystem does not have an interactive host associated
# with it, thus standard Write-Host and other host-based cmdlets have no place
# to write to. This knowledge is used to tell if the script is in an Agent
# or if it is running on a standard PowerShell host.
$isNotConsole = ($host.Name -ne "ConsoleHost")
function Get-IsAgentStep
{
$global:isNotConsole
}
# Writing to the agent logs is easiest to achieve with [Console]::Error.WriteLine
# If the script is in Agent, write through the Console directly. If the script
# is not in Agent (someone is using it to debug), then just output to the pipeline.
function Write-AgentLog($object)
{
if(Get-IsAgentStep)
{
[Console]::Error.WriteLine($object)
}
else
{
$object
}
}
# Query the given WMI object and report pass or fail on the object.
function Validate-WmiObject([string] $wmiObject)
{
process
{
Write-AgentLog "#Running Command:"
Write-AgentLog "Get-WmiObject $wmiObject | Out-Null"
# Use ErrorVariable and ErrorAction SilentlyContinue so that all of the
# objects can be tested without stopping the script or having spurrious messages
# in the Agent logs.
Get-WmiObject $wmiObject -ErrorVariable wmiError -ErrorAction SilentlyContinue | Out-Null
# Check the error message and report pass or fail
if($wmiError)
{
$global:errorHappened=$true
Write-AgentLog "#Command FAILED. Exception : $wmiError"
}
else
{
Write-AgentLog "#Command PASSED."
}
}
}
# Validate all of the Wmi objects. If any one of them fail, then
# report an error.
function Validate-AllWmiObjects
{
$objectsToValidate | %{
Validate-WmiObject $_
}
if($global:errorHappened)
{
Write-Error -ErrorAction Stop "One or more WMI classes failed the test"
}
}
# Automatically check the status of the objects if the script is running in Agent
# Otherwise, allow the user to call the Validate functions interactively.
if(Get-IsAgentStep)
{
Validate-AllWmiObjects
}
'
END
GO
----------------------------------------------------------------------
-- A sp that creates a job that ensures that WMI works appropreately for
-- Utility data collection.
----------------------------------------------------------------------
IF OBJECT_ID ('dbo.sp_sysutility_mi_create_job_validate_wmi') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_mi_create_job_validate_wmi]', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_create_job_validate_wmi]
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_mi_create_job_validate_wmi]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_create_job_validate_wmi]
AS
BEGIN
DECLARE @job_name sysname = N'sysutility_mi_validate_wmi'
DECLARE @job_id uniqueidentifier
DECLARE @description nvarchar(512) = N''
DECLARE @psScript NVARCHAR(MAX) = (SELECT [dbo].[fn_sysutility_mi_get_validate_wmi_script]());
-- Delete the job if it already exists
WHILE (EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @job_name))
BEGIN
EXEC sp_delete_job @job_name=@job_name
END
-- Create the job
EXEC msdb.dbo.sp_add_job @job_name=@job_name,
@enabled=1,
@notify_level_eventlog=0,
@notify_level_email=2,
@notify_level_netsend=2,
@notify_level_page=2,
@delete_level=0,
@category_id=0,
@job_id = @job_id OUTPUT
EXEC msdb.dbo.sp_add_jobserver @job_name=@job_name, @server_name = @@SERVERNAME
-- Add the validation step
EXEC msdb.dbo.sp_add_jobstep
@job_id=@job_id,
@step_name=N'Validate WMI configuration',
@step_id=1,
@cmdexec_success_code=0,
@on_fail_action=2,
@on_fail_step_id=0,
@on_success_action=1,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'Powershell',
@command=@psScript
END
GO
------------------------------------------------------------------------
-- SP to create the job which creates the UtilityCacheDirectory
------------------------------------------------------------------------
IF OBJECT_ID ('dbo.sp_sysutility_mi_create_cache_directory') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_mi_create_cache_directory]', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_create_cache_directory]
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_mi_create_cache_directory]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_create_cache_directory]
@network_account sysname,
@agent_service_account sysname
AS
BEGIN
DECLARE @instance_name nvarchar(128)
DECLARE @null_column sysname
SET @null_column = NULL
IF (@network_account IS NULL OR @network_account = N'')
SET @null_column = '@network_account'
ELSE IF (@agent_service_account IS NULL OR @agent_service_account = N'')
SET @null_column = '@agent_service_account'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_create_cache_directory_job')
RETURN(1)
END
SET @instance_name = ISNULL(CONVERT(nvarchar(128), SERVERPROPERTY('InstanceName')), N'MSSQLSERVER')
DECLARE @job_name sysname
DECLARE @job_id uniqueidentifier
DECLARE @description nvarchar(512)
DECLARE @cachepath nvarchar(2048); -- SQL Eye reports that xp_instance_regread can truncate the cachepath
-- but xp_instance_regread doesn't handle LOB types to use nvarchar(MAX)
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent', N'WorkingDirectory', @cachepath OUTPUT;
set @cachepath=@cachepath + '\UtilityDC'
RAISERROR (@cachepath, 0, 1) WITH NOWAIT;
-- create unique job name
SET @job_name = N'sysutility_create_cache_directory'
WHILE (EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = @job_name))
BEGIN
EXEC sp_delete_job @job_name=@job_name
END
EXEC msdb.dbo.sp_add_job @job_name=@job_name,
@enabled=1,
@notify_level_eventlog=0,
@notify_level_email=2,
@notify_level_netsend=2,
@notify_level_page=2,
@delete_level=0,
@category_id=0,
@job_id = @job_id OUTPUT
DECLARE @server_name SYSNAME = CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))
EXEC msdb.dbo.sp_add_jobserver @job_name=@job_name, @server_name = @server_name
DECLARE @command nvarchar(MAX)
SET @command = N'if exist "' + @cachepath + '" rmdir /S /Q "' + @cachepath + '"'
EXEC msdb.dbo.sp_add_jobstep
@job_id=@job_id,
@step_name=N'Delete existing cache directory',
@step_id=1,
@cmdexec_success_code=0,
@on_fail_action=2,
@on_fail_step_id=0,
@on_success_action=3,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'CMDEXEC',
@command=@command,
@flags=16
IF NOT (@network_account LIKE @agent_service_account)
BEGIN
-- If network_account (proxy) and agent_service_account are different, we shall ACL the cache
RAISERROR ('network_account is different from agent_service_account', 0, 1) WITH NOWAIT;
SET @command = N'md "' + @cachepath + '"'
EXEC msdb.dbo.sp_add_jobstep
@job_id=@job_id,
@step_name=N'Create cache directory',
@step_id=2,
@cmdexec_success_code=0,
@on_fail_action=2,
@on_fail_step_id=0,
@on_success_action=3,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'CMDEXEC',
@command=@command,
@flags=16
SET @command = N'cacls "' + @cachepath + '" /E /G ' + @network_account + ':C'
EXEC msdb.dbo.sp_add_jobstep
@job_id=@job_id,
@step_name=N'ACL cache directory',
@step_id=3,
@cmdexec_success_code=0,
@on_fail_action=2,
@on_fail_step_id=0,
@on_success_action=1,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'CMDEXEC',
@command=@command,
@flags=16
END
ELSE
BEGIN
-- If network_account (proxy) and agent_service_account are the same, then there is no need to ACL the cache
-- as the account already has write access to it courtesy the agent service account provisioning.
-- In this case explicit provisioning of cache with the account leads to error.
RAISERROR ('network_account is the same as the agent_service_account', 0, 1) WITH NOWAIT;
SET @command = N'md "' + @cachepath + '"'
EXEC msdb.dbo.sp_add_jobstep
@job_id=@job_id,
@step_name=N'Create cache directory',
@step_id=2,
@cmdexec_success_code=0,
@on_fail_action=2,
@on_fail_step_id=0,
@on_success_action=1,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'CMDEXEC',
@command=@command,
@flags=16
END
END
GO
---------------------------------------------------------------------
-- Table to hold information about a managed instance and its
-- configuration
---------------------------------------------------------------------
IF NOT EXISTS (SELECT name FROM [sys].[objects] WHERE object_id = OBJECT_ID(N'[dbo].[sysutility_mi_configuration_internal]') AND type in (N'U'))
BEGIN
RAISERROR('Creating [dbo].[sysutility_mi_configuration_internal] table', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_mi_configuration_internal]
(
-- configuration_id + pk enforces a single row in the table
configuration_id AS (1),
ucp_instance_name SYSNAME NULL,
mdw_database_name SYSNAME NULL,
CONSTRAINT pk_sysutility_mi_configuration_internal_configuration_id PRIMARY KEY (configuration_id)
-- this table should only contain one row
);
END
GO
IF (NOT OBJECT_ID('[dbo].[sysutility_mi_configuration]', 'V') IS NULL)
BEGIN
RAISERROR('Dropping [dbo].[sysutility_mi_configuration] view', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_mi_configuration]
END
GO
RAISERROR('Creating [dbo].[sysutility_mi_configuration] view', 0, 1) WITH NOWAIT;
GO
CREATE VIEW [dbo].[sysutility_mi_configuration]
AS
SELECT config.ucp_instance_name, config.mdw_database_name, t.upload_schema_version
FROM
-- The upload_schema_version represents the contract between the UCP and MI for data upload
-- Change this value when a breaking change with a (downlevel) UCP may be introduced in the MI
-- upload code.
(SELECT 100 AS upload_schema_version) t
LEFT OUTER JOIN
[dbo].[sysutility_mi_configuration_internal] config
ON 1=1
GO
----------------------------------------------------------
-- Stored PROCs to add/removed/check the UCP configuration
----------------------------------------------------------
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_sysutility_mi_add_ucp_registration]') AND type in (N'P', N'PC'))
BEGIN
RAISERROR('Dropping [dbo].[sp_sysutility_mi_add_ucp_registration] procedure', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_add_ucp_registration];
END
GO
RAISERROR('Creating [dbo].[sp_sysutility_mi_add_ucp_registration] procedure', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_add_ucp_registration]
@ucp_instance_name SYSNAME,
@mdw_database_name SYSNAME
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @null_column SYSNAME = NULL
SET NOCOUNT ON;
SET XACT_ABORT ON;
IF (@ucp_instance_name IS NULL)
SET @null_column = '@ucp_instance_name'
ELSE IF (@mdw_database_name IS NULL)
SET @null_column = '@mdw_database_name'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_mi_add_ucp_registration')
RETURN(1)
END
BEGIN TRANSACTION;
IF EXISTS (SELECT * FROM [msdb].[dbo].[sysutility_mi_configuration_internal])
BEGIN
UPDATE [msdb].[dbo].[sysutility_mi_configuration_internal]
SET
ucp_instance_name = @ucp_instance_name,
mdw_database_name = @mdw_database_name
END
ELSE
BEGIN
INSERT INTO [msdb].[dbo].[sysutility_mi_configuration_internal] (ucp_instance_name, mdw_database_name)
VALUES (@ucp_instance_name, @mdw_database_name);
END
COMMIT TRANSACTION;
---- Add the MiUcpName registry key values.
---- If the value is already present this XP will update them.
EXEC master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'MiUcpName',
N'REG_SZ',
@ucp_instance_name
END
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_sysutility_mi_remove_ucp_registration]') AND type in (N'P', N'PC'))
BEGIN
RAISERROR('Dropping [dbo].[sp_sysutility_mi_remove_ucp_registration] procedure', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_remove_ucp_registration];
END
GO
RAISERROR('Creating [dbo].[sp_sysutility_mi_remove_ucp_registration] procedure', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_remove_ucp_registration]
WITH EXECUTE AS OWNER
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
BEGIN TRANSACTION;
IF EXISTS (SELECT * FROM [msdb].[dbo].[sysutility_mi_configuration_internal])
BEGIN
UPDATE [msdb].[dbo].[sysutility_mi_configuration_internal]
SET
ucp_instance_name = NULL,
mdw_database_name = NULL
END
ELSE
BEGIN
INSERT INTO [msdb].[dbo].[sysutility_mi_configuration_internal] (ucp_instance_name, mdw_database_name)
VALUES (NULL, NULL);
END
COMMIT TRANSACTION;
---- If the above part fails it will not execute the following XPs.
---- The following XP calls are not transactional, so they are put outside
---- the transaction.
---- Remove the MiUcpName registry key if it is present
DECLARE @mi_ucp_name nvarchar(1024)
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'MiUcpName',
@mi_ucp_name OUTPUT
IF @mi_ucp_name IS NOT NULL
BEGIN
EXEC master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'MiUcpName'
END
---- Remove the registry key if this instance is NOT a UCP.
---- If this instance is a UCP we cannot remove the key entirely as
---- the version number is still stored under the key.
IF (msdb.dbo.fn_sysutility_get_is_instance_ucp() = 0)
BEGIN
EXEC master.dbo.xp_instance_regdeletekey N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility'
END
END
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fn_sysutility_ucp_get_instance_is_mi]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
BEGIN
RAISERROR('Dropping [dbo].[fn_sysutility_ucp_get_instance_is_mi] function', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysutility_ucp_get_instance_is_mi];
END
GO
RAISERROR('Creating [dbo].[fn_sysutility_ucp_get_instance_is_mi] function', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_ucp_get_instance_is_mi]()
RETURNS BIT
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @status BIT = (SELECT
CASE
WHEN ((ucp_instance_name IS NOT NULL) AND (mdw_database_name IS NOT NULL)) THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT)
END
FROM sysutility_mi_configuration_internal config)
RETURN ISNULL(@status,0)
END
GO
----------------------------------------------------------------------------------
-- Table sysutility_mi_dac_execution_statistics_internal
-- Staging table used to store execution statistics for DACs on the local instance. This table stores
-- relatively transient data; in the worst case, dropping and recreating it will result in the loss of
-- up to one upload interval (15 minutes) of DAC execution statistics. The data in this table is created
-- and updated by sp_sysutility_mi_collect_dac_execution_statistics_internal, which runs every 15 seconds
-- on each MI. The data is harvested every 15 min by sp_sysutility_mi_get_dac_execution_statistics_internal,
-- then moved to the UCP's CMDW database by the Utility collection set.
----------------------------------------------------------------------------------
IF OBJECT_ID ('dbo.sysutility_mi_dac_execution_statistics_internal', 'U') IS NOT NULL
BEGIN
RAISERROR('Dropping [dbo].[sysutility_mi_dac_execution_statistics_internal] table', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_mi_dac_execution_statistics_internal];
END
GO
RAISERROR('Creating [dbo].[sysutility_mi_dac_execution_statistics_internal] table', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_mi_dac_execution_statistics_internal]
(
dac_instance_name sysname NOT NULL,
database_name sysname UNIQUE NOT NULL, -- database name, from sysdac_instances
database_id int UNIQUE NOT NULL, -- database ID, from sysdac_instances
date_created datetime NULL, -- DAC creation date, from sysdac_instances
[description] nvarchar(4000) NULL, -- DAC description, from sysdac_instances
first_collection_time datetimeoffset NULL, -- date and time of the first update by [sp_sysutility_mi_collect_dac_execution_statistics_internal]
last_collection_time datetimeoffset NULL, -- date and time of the last update by [sp_sysutility_mi_collect_dac_execution_statistics_internal]
last_upload_time datetimeoffset NULL, -- date and time of the last upload of this data by DC
lifetime_cpu_time_ms bigint NULL, -- cumulative CPU time observed within this DAC since [first_collection_time]
cpu_time_ms_at_last_upload bigint NULL, -- [lifetime_cpu_time_ms] value at the last DC upload
CONSTRAINT PK_sysutility_mi_dac_execution_statistics_internal PRIMARY KEY CLUSTERED (dac_instance_name)
);
GO
----------------------------------------------------------------------------------
-- Table dbo.sysutility_mi_session_statistics_internal
-- This table is effectively part of the implementation of sp_sysutility_mi_collect_dac_execution_statistics_internal.
-- We can safely drop it because it holds ephemeral data that does not need to be preserved across
-- an msdb upgrade. The only reason we need a separate table here is because we must temporarily
-- store execution statistics at the session level in order to approximate the database/DAC execution
-- statistics (SQL doesn't automatically roll execution stats up to the database level).
----------------------------------------------------------------------------------
IF (OBJECT_ID ('dbo.sysutility_mi_session_statistics_internal', 'U') IS NOT NULL)
BEGIN
RAISERROR('Dropping table [dbo].[sysutility_mi_session_statistics_internal]', 0, 1) WITH NOWAIT;
DROP TABLE [dbo].[sysutility_mi_session_statistics_internal];
END;
GO
IF (OBJECT_ID ('dbo.sysutility_mi_session_statistics_internal', 'U') IS NULL)
BEGIN
RAISERROR('Creating table [dbo].[sysutility_mi_session_statistics_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE dbo.sysutility_mi_session_statistics_internal (
collection_time datetimeoffset NOT NULL,
session_id int NOT NULL,
dac_instance_name sysname NOT NULL,
database_name sysname NOT NULL,
login_time datetime NOT NULL,
cumulative_cpu_ms int NOT NULL,
CONSTRAINT PK_sysutility_mi_session_statistics_internal PRIMARY KEY CLUSTERED
(collection_time, session_id, dac_instance_name, database_name, login_time)
);
END;
GO
-------------------------------------------------------------------------------------
-- Configuration table to snapshot partitioning to enhance the performance of caching job
-- time_id = 1 means the previous snapshot cut, time_id = 0, means the current snapshot_id cut
-- Preserve the table during upgrade scenarios (create if it doesn't exist)
-------------------------------------------------------------------------------------
IF(OBJECT_ID(N'[dbo].[sysutility_ucp_snapshot_partitions_internal]', 'U') IS NULL)
BEGIN
RAISERROR('Creating [dbo].[sysutility_ucp_snapshot_partitions_internal] table', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_snapshot_partitions_internal]
(
time_id INT,
latest_consistent_snapshot_id INT,
);
END
GO
----------------------------------------------------------------------------------
-- Procedure dbo.sp_sysutility_mi_collect_dac_execution_statistics_internal
-- Captures execution statistics (currently, just CPU usage) by sessions within each DAC since the last
-- execution of this sp. The incremental new CPU usage is added to the the lifetime DAC total CPU usage
-- recorded in the cache table [sysutility_mi_dac_execution_statistics_internal]. This sp is executed
-- by the Agent job that runs every 15 seconds on a Utility managed instance. The output (the execution
-- stats in the cache table) is harvested by sp_sysutility_mi_get_dac_execution_statistics_internal as
-- part of Utility's Data Collector collection set.
--
-- Parameters: None
-- Output Resultsets: None
----------------------------------------------------------------------------------
IF OBJECT_ID('dbo.sp_sysutility_mi_collect_dac_execution_statistics_internal', 'P') IS NOT NULL
BEGIN
RAISERROR('Dropping [dbo].[sp_sysutility_mi_collect_dac_execution_statistics_internal] procedure', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_collect_dac_execution_statistics_internal];
END
GO
RAISERROR('Creating [dbo].[sp_sysutility_mi_collect_dac_execution_statistics_internal] procedure', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_collect_dac_execution_statistics_internal]
AS
BEGIN
DECLARE @current_collection_time datetimeoffset = SYSDATETIMEOFFSET();
DECLARE @previous_collection_time datetimeoffset;
-- At this point the session stats table should contain only rows from the prior collection time (or no
-- rows, in which case @previous_collection_time will be set to NULL). Retrieve the prior collection time.
SELECT TOP 1 @previous_collection_time = collection_time
FROM dbo.sysutility_mi_session_statistics_internal
ORDER BY collection_time DESC;
-- Get a list of the DACs deployed on this instance. In the sysdac_instances view, some of these values
-- are unindexed computed columns. Store them in a temp table so that we get indexed retrieval by dbid
-- or db/instance name and stats on the columns we'll use as join columns.
CREATE TABLE #dacs (
dac_instance_name sysname PRIMARY KEY,
database_name sysname UNIQUE,
database_id int UNIQUE,
date_created datetime,
[description] nvarchar(4000));
INSERT INTO #dacs
SELECT DISTINCT
instance_name,
database_name,
DB_ID(database_name),
date_created,
[description]
FROM dbo.sysdac_instances
-- Filter out "orphaned" DACs that have had their database deleted or renamed
WHERE DB_ID(database_name) IS NOT NULL;
-- Step 1: Capture execution stats for all current sessions in DAC databases. Now this table should
-- hold two snapshots: one that we just inserted (referred to as the "current" data from here on), and
-- the immediately prior snapshot of the same data from ~15 seconds ago ("previous"). Note that we
-- include a dummy row with a fake spid number for any DACs that don't have any active sessions. This
-- is because of a downstream requirement that we return a row for all DACs, even if there are no stats
-- to report for the DAC.
INSERT INTO dbo.sysutility_mi_session_statistics_internal
(collection_time, session_id, dac_instance_name, database_name, login_time, cumulative_cpu_ms)
SELECT
@current_collection_time,
ISNULL (sp.spid, -10) AS session_id,
#dacs.dac_instance_name,
#dacs.database_name,
ISNULL (sp.login_time, GETDATE()) AS login_time,
ISNULL (SUM(sp.cpu), 0) AS cumulative_cpu_ms
FROM #dacs
LEFT OUTER JOIN sys.sysprocesses AS sp ON #dacs.database_id = sp.[dbid]
GROUP BY ISNULL (sp.spid, -10), #dacs.dac_instance_name, #dacs.database_name, ISNULL (sp.login_time, GETDATE());
-- Step 2: If this is the first execution, set @prev_collection_time to @cur_collection_time.
-- This has the effect of generating stats that indicate no work done for all DACs. This is
-- the best we can do on the first execution because we need to snapshots in order to calculate
-- correct resource consumption over a time interval. We can't just return here, because we
-- need at least a "stub" row for each DAC, so they all DACs will appear in the UI if a DC
-- upload runs before our next collection time.
IF (@previous_collection_time IS NULL)
BEGIN
SET @previous_collection_time = @current_collection_time;
END;
-- Step 3: Determine the amount of new CPU time used by each DAC in the just-completed ~15 second interval
-- (this defines a CTE that is used in the following step).
WITH interval_dac_statistics AS (
SELECT
#dacs.dac_instance_name,
-- Add up the approximate CPU time used by each session since the last execution of this proc.
-- The [current CPU] - [previous CPU] calculation for a session will return NULL if
-- [previous CPU] is NULL ([current CPU] should never be NULL). Previous CPU might be
-- NULL if the session is new. Previous CPU could also be NULL if an existing session
-- changed database context. In either case, we will not charge any of the session's
-- CPU time to the database for this interval. We will start charging any new session
-- CPU time to the session's current database on the next execution of this procedure,
-- assuming that the session doesn't change database context between now and then.
SUM (ISNULL (cur.cumulative_cpu_ms - prev.cumulative_cpu_ms, 0)) AS interval_cpu_time_ms,
#dacs.database_name,
#dacs.database_id,
#dacs.date_created,
#dacs.[description]
FROM #dacs
LEFT OUTER JOIN dbo.sysutility_mi_session_statistics_internal AS cur -- current snapshot, "right" side of time interval
ON #dacs.dac_instance_name = cur.dac_instance_name AND cur.collection_time = @current_collection_time
LEFT OUTER JOIN dbo.sysutility_mi_session_statistics_internal AS prev -- previous snapshot, "left" side of time interval
ON cur.dac_instance_name = prev.dac_instance_name AND prev.collection_time = @previous_collection_time
AND cur.session_id = prev.session_id AND cur.login_time = prev.login_time
GROUP BY #dacs.dac_instance_name, #dacs.database_name, #dacs.database_id, #dacs.date_created, #dacs.[description]
)
-- Step 4: Do an "upsert" to the staging table. If the DAC is already represented in this table, we will
-- add our interval CPU time to that row's [lifetime_cpu_time_ms] value. If the DAC does not yet exist
-- in the staging table, we will insert a new row.
--
-- A note about overflow risk for the [lifetime_cpu_time_ms] column (bigint). A DAC that used 100% of
-- every CPU on a 500 processor machine 24 hours a day could run for more than half a million years without
-- overflowing this column.
MERGE [dbo].[sysutility_mi_dac_execution_statistics_internal] AS [target]
USING interval_dac_statistics AS [source]
ON [source].dac_instance_name = [target].dac_instance_name
-- Filter out "orphaned" DACs that have had their database deleted or renamed
AND DB_ID([target].database_name) IS NOT NULL
WHEN MATCHED THEN UPDATE
SET [target].lifetime_cpu_time_ms = ISNULL([target].lifetime_cpu_time_ms, 0) + [source].interval_cpu_time_ms,
[target].last_collection_time = @current_collection_time,
[target].first_collection_time = ISNULL ([target].first_collection_time, @previous_collection_time),
[target].database_name = [source].database_name,
[target].database_id = [source].database_id,
[target].date_created = [source].date_created,
[target].[description] = [source].[description]
WHEN NOT MATCHED BY TARGET THEN INSERT ( -- new DAC
dac_instance_name,
first_collection_time,
last_collection_time,
last_upload_time,
lifetime_cpu_time_ms,
cpu_time_ms_at_last_upload,
database_name,
database_id,
date_created,
[description])
VALUES (
[source].dac_instance_name,
@previous_collection_time,
@current_collection_time,
@previous_collection_time,
[source].interval_cpu_time_ms,
0,
[source].database_name,
[source].database_id,
[source].date_created,
[source].[description])
WHEN NOT MATCHED BY SOURCE THEN DELETE; -- deleted or orphaned DAC
-- Step 5: Delete the session stats from the previous collection time as we no longer need them (but keep the
-- current stats we just collected in Step 1; at the next collection time these will be the "previous"
-- stats that we'll use to calculate the stats for the next interval).
DELETE FROM dbo.sysutility_mi_session_statistics_internal WHERE collection_time != @current_collection_time;
END;
GO
----------------------------------------------------------------------------------
-- Procedure dbo.sp_sysutility_mi_get_dac_execution_statistics_internal
-- Retrieves execution statistics (currently, just CPU usage) for each DAC on the local managed instance.
-- The CPU usage values are updated in the staging table [sysutility_mi_dac_execution_statistics_internal]
-- by the [sp_sysutility_mi_collect_dac_execution_statistics_internal] stored proc. This stored proc is
-- executed by Utility's Data Collector collection set. This sp returns an output resultset, but cannot
-- be implemented as a TVF because it has side effects (records its last upload time in the staging table).
--
-- Parameters: None
-- Output Resultsets: A data set containing metadata and execution statistics for each DAC on this managed
-- instance
----------------------------------------------------------------------------------
IF OBJECT_ID('dbo.sp_sysutility_mi_get_dac_execution_statistics_internal', 'P') IS NOT NULL
BEGIN
RAISERROR('Dropping [dbo].[sp_sysutility_mi_get_dac_execution_statistics_internal] procedure', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_get_dac_execution_statistics_internal];
END;
GO
RAISERROR('Creating [dbo].[sp_sysutility_mi_get_dac_execution_statistics_internal] procedure', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_get_dac_execution_statistics_internal]
AS
BEGIN
SET NOCOUNT ON; -- Required for SSIS to retrieve the proc's output rowset
DECLARE @logical_processor_count int;
SELECT @logical_processor_count = cpu_count FROM sys.dm_os_sys_info;
-- Get the shared "batch time" that will be a part of all data collection query rowsets. On the UCP, this
-- will be used to tie together all of the data from one execution of the MI data collection job.
-- Check for the existance of the temp table. If it is there, then the Utility is
-- set up correctly. If it is not there, do not fail the upload. This handles the
-- case when a user might run the collection set out-of-band from the Utility.
-- The data may not be staged, but no sporratic errors should occur
DECLARE @current_batch_time datetimeoffset(7) = SYSDATETIMEOFFSET();
IF OBJECT_ID ('[tempdb].[dbo].[sysutility_batch_time_internal]') IS NOT NULL
BEGIN
SELECT @current_batch_time = latest_batch_time FROM tempdb.dbo.sysutility_batch_time_internal;
END
-- Temp storage for the DAC execution statistics for this data collection interval (typically, a 15 minute window).
-- This and the following table variable would be better as a temp table (b/c of the potentially large number
-- of rows), but this proc is run by DC with SET FMTONLY ON to get the output rowset schema. That means no
-- temp tables.
DECLARE @upload_interval_dac_stats TABLE (
dac_instance_name sysname PRIMARY KEY,
lifetime_cpu_time_ms bigint NULL, -- amount of CPU time consumed since we started tracking this DAC
interval_cpu_time_ms bigint NULL, -- amount of CPU time used by the DAC in this ~15 min upload interval
interval_start_time datetimeoffset NULL,
interval_end_time datetimeoffset NULL
);
-- We use an update with an OUTPUT clause to atomically update the staging table and retrieve data from it.
-- The use of the "inserted"/"deleted" pseudo-tables in this query ensures that we don't lose any data if the
-- collection job happens to be running at the same time.
UPDATE dbo.sysutility_mi_dac_execution_statistics_internal
SET last_upload_time = SYSDATETIMEOFFSET(),
cpu_time_ms_at_last_upload = lifetime_cpu_time_ms
OUTPUT
inserted.dac_instance_name,
inserted.lifetime_cpu_time_ms,
-- Calculate the amount of CPU time consumed by this DAC since the last time we did an upload.
(inserted.cpu_time_ms_at_last_upload - ISNULL (deleted.cpu_time_ms_at_last_upload, 0)) AS interval_cpu_time_ms,
deleted.last_upload_time AS interval_start_time,
inserted.last_upload_time AS interval_end_time
INTO @upload_interval_dac_stats;
-- Return the data to the collection set
SELECT
CONVERT (sysname, SERVERPROPERTY('ComputerNamePhysicalNetBIOS')) AS physical_server_name,
CONVERT (sysname, SERVERPROPERTY('ServerName')) AS server_instance_name,
CONVERT (sysname, dacs.database_name) AS dac_db,
dacs.date_created AS dac_deploy_date,
dacs.[description] AS dac_description,
dacs.dac_instance_name AS dac_name,
dac_stats.interval_start_time,
dac_stats.interval_end_time,
dac_stats.interval_cpu_time_ms,
CONVERT (real, CASE
WHEN dac_stats.interval_cpu_time_ms IS NOT NULL
AND DATEDIFF (second, dac_stats.interval_start_time, dac_stats.interval_end_time) > 0
-- % CPU calculation is: [avg seconds of cpu time used per processor] / [interval duration in sec]
-- The percentage value is returned as an int (e.g. 76 for 76%, not 0.76)
THEN 100 * (dac_stats.interval_cpu_time_ms / @logical_processor_count) / 1000 /
DATEDIFF (second, dac_stats.interval_start_time, dac_stats.interval_end_time)
ELSE 0
END) AS interval_cpu_pct,
dac_stats.lifetime_cpu_time_ms,
@current_batch_time AS batch_time
FROM dbo.sysutility_mi_dac_execution_statistics_internal AS dacs
LEFT OUTER JOIN @upload_interval_dac_stats AS dac_stats ON dacs.dac_instance_name = dac_stats.dac_instance_name;
END;
GO
----------------------------------------------------------------------------
--- Function to get a readable processor architecture from stored architecture number
----------------------------------------------------------------------------
IF EXISTS (SELECT name FROM [sys].[objects] WHERE object_id = OBJECT_ID(N'[dbo].[fn_sysutility_mi_get_cpu_architecture_name]'))
DROP FUNCTION [dbo].[fn_sysutility_mi_get_cpu_architecture_name];
GO
CREATE FUNCTION [dbo].[fn_sysutility_mi_get_cpu_architecture_name](@architecture INT)
RETURNS NVARCHAR(64)
AS
BEGIN
DECLARE @architecture_name NVARCHAR(64) = N''
SELECT @architecture_name =
CASE
WHEN @architecture = 0 THEN 'x86'
WHEN @architecture = 1 THEN 'MIPS'
WHEN @architecture = 2 THEN 'Alpha'
WHEN @architecture = 3 THEN 'PowerPC'
WHEN @architecture = 6 THEN 'Intel Itanium Processor Family (IPF)'
WHEN @architecture = 9 THEN 'x64'
END
RETURN @architecture_name
END
GO
----------------------------------------------------------------------------
--- Function to get a readable processor family from stored family number
----------------------------------------------------------------------------
IF EXISTS (SELECT name FROM [sys].[objects] WHERE object_id = OBJECT_ID(N'[dbo].[fn_sysutility_mi_get_cpu_family_name]'))
DROP FUNCTION [dbo].[fn_sysutility_mi_get_cpu_family_name];
GO
CREATE FUNCTION [dbo].[fn_sysutility_mi_get_cpu_family_name](@family INT)
RETURNS NVARCHAR(128)
AS
BEGIN
DECLARE @family_name NVARCHAR(128) = N''
SELECT @family_name =
CASE
WHEN @family = 1 THEN 'Other'
WHEN @family = 2 THEN 'Unknown'
WHEN @family = 3 THEN '8086'
WHEN @family = 4 THEN '80286'
WHEN @family = 5 THEN 'Intel386 Processor'
WHEN @family = 6 THEN 'Intel486 Processor'
WHEN @family = 7 THEN '8087'
WHEN @family = 8 THEN '80287'
WHEN @family = 9 THEN '80387'
WHEN @family = 10 THEN '80487'
WHEN @family = 11 THEN 'Pentium Brand'
WHEN @family = 12 THEN 'Pentium Pro'
WHEN @family = 13 THEN 'Pentium II'
WHEN @family = 14 THEN 'Pentium Processor with MMX Technology'
WHEN @family = 15 THEN 'Celeron'
WHEN @family = 16 THEN 'Pentium II Xeon'
WHEN @family = 17 THEN 'Pentium III'
WHEN @family = 18 THEN 'M1 Family'
WHEN @family = 19 THEN 'M2 Family'
WHEN @family = 24 THEN 'AMD Duron Processor Family'
WHEN @family = 25 THEN 'K5 Family'
WHEN @family = 26 THEN 'K6 Family'
WHEN @family = 27 THEN 'K6-2'
WHEN @family = 28 THEN 'K6-3'
WHEN @family = 29 THEN 'AMD Athlon Processor Family'
WHEN @family = 30 THEN 'AMD2900 Family'
WHEN @family = 31 THEN 'K6-2+'
WHEN @family = 32 THEN 'Power PC Family'
WHEN @family = 33 THEN 'Power PC 601'
WHEN @family = 34 THEN 'Power PC 603'
WHEN @family = 35 THEN 'Power PC 603+'
WHEN @family = 36 THEN 'Power PC 604'
WHEN @family = 37 THEN 'Power PC 620'
WHEN @family = 38 THEN 'Power PC X704'
WHEN @family = 39 THEN 'Power PC 750'
WHEN @family = 48 THEN 'Alpha Family'
WHEN @family = 49 THEN 'Alpha 21064'
WHEN @family = 50 THEN 'Alpha 21066'
WHEN @family = 51 THEN 'Alpha 21164'
WHEN @family = 52 THEN 'Alpha 21164PC'
WHEN @family = 53 THEN 'Alpha 21164a'
WHEN @family = 54 THEN 'Alpha 21264'
WHEN @family = 55 THEN 'Alpha 21364'
WHEN @family = 64 THEN 'MIPS Family'
WHEN @family = 65 THEN 'MIPS R4000'
WHEN @family = 66 THEN 'MIPS R4200'
WHEN @family = 67 THEN 'MIPS R4400'
WHEN @family = 68 THEN 'MIPS R4600'
WHEN @family = 69 THEN 'MIPS R10000'
WHEN @family = 80 THEN 'SPARC Family'
WHEN @family = 81 THEN 'SuperSPARC'
WHEN @family = 82 THEN 'microSPARC II'
WHEN @family = 83 THEN 'microSPARC IIep'
WHEN @family = 84 THEN 'UltraSPARC'
WHEN @family = 85 THEN 'UltraSPARC II'
WHEN @family = 86 THEN 'UltraSPARC IIi'
WHEN @family = 87 THEN 'UltraSPARC III'
WHEN @family = 88 THEN 'UltraSPARC IIIi'
WHEN @family = 96 THEN '68040'
WHEN @family = 97 THEN '68xxx Family'
WHEN @family = 98 THEN '68000'
WHEN @family = 99 THEN '68010'
WHEN @family = 100 THEN '68020'
WHEN @family = 101 THEN '68030'
WHEN @family = 112 THEN 'Hobbit Family'
WHEN @family = 120 THEN 'Crusoe TM5000 Family'
WHEN @family = 121 THEN 'Crusoe TM3000 Family'
WHEN @family = 122 THEN 'Efficeon TM8000 Family'
WHEN @family = 128 THEN 'Weitek'
WHEN @family = 130 THEN 'Itanium Processor'
WHEN @family = 131 THEN 'AMD Athlon 64 Processor Family'
WHEN @family = 132 THEN 'AMD Opteron Processor Family'
WHEN @family = 144 THEN 'PA-RISC Family'
WHEN @family = 145 THEN 'PA-RISC 8500'
WHEN @family = 146 THEN 'PA-RISC 8000'
WHEN @family = 147 THEN 'PA-RISC 7300LC'
WHEN @family = 148 THEN 'PA-RISC 7200'
WHEN @family = 149 THEN 'PA-RISC 7100LC'
WHEN @family = 150 THEN 'PA-RISC 7100'
WHEN @family = 160 THEN 'V30 Family'
WHEN @family = 176 THEN 'Pentium III Xeon Processor'
WHEN @family = 177 THEN 'Pentium III Processor with Intel SpeedStep Technology'
WHEN @family = 178 THEN 'Pentium 4'
WHEN @family = 179 THEN 'Intel Xeon'
WHEN @family = 180 THEN 'AS400 Family'
WHEN @family = 181 THEN 'Intel Xeon Processor MP'
WHEN @family = 182 THEN 'AMD Athlon XP Family'
WHEN @family = 183 THEN 'AMD Athlon MP Family'
WHEN @family = 184 THEN 'Intel Itanium 2'
WHEN @family = 185 THEN 'Intel Pentium M Processor'
WHEN @family = 190 THEN 'K7'
WHEN @family = 200 THEN 'IBM390 Family'
WHEN @family = 201 THEN 'G4'
WHEN @family = 202 THEN 'G5'
WHEN @family = 203 THEN 'G6'
WHEN @family = 204 THEN 'z/Architecture Base'
WHEN @family = 250 THEN 'i860'
WHEN @family = 251 THEN 'i960'
WHEN @family = 260 THEN 'SH-3'
WHEN @family = 261 THEN 'SH-4'
WHEN @family = 280 THEN 'ARM'
WHEN @family = 281 THEN 'StrongARM'
WHEN @family = 300 THEN '6x86'
WHEN @family = 301 THEN 'MediaGX'
WHEN @family = 302 THEN 'MII'
WHEN @family = 320 THEN 'WinChip'
WHEN @family = 350 THEN 'DSP'
WHEN @family = 500 THEN 'Video Processor'
END
RETURN @family_name
END
GO
IF (OBJECT_ID(N'[msdb].[dbo].[sysutility_mi_volumes_stage_internal]', N'U') IS NULL)
BEGIN
RAISERROR('Creating [dbo].[sysutility_mi_volumes_stage_internal] table', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_mi_volumes_stage_internal]
(
-- Collected columns
[volume_device_id] SYSNAME NOT NULL DEFAULT N'', -- Collected as String
[volume_name] NVARCHAR(260) NOT NULL DEFAULT N'', -- Collected as String
[capacity_mb] DECIMAL(20,0) NOT NULL DEFAULT 0.0, -- Collected as UInt64
[free_space_mb] DECIMAL(20,0) NOT NULL DEFAULT 0.0, -- Collected as UInt64
-- Computed columns
[server_instance_name] AS (CAST(SERVERPROPERTY('ServerName') AS SYSNAME)),
[virtual_server_name] AS (CAST(SERVERPROPERTY('MachineName') AS SYSNAME)),
[physical_server_name] AS (CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS SYSNAME))
);
END
GO
IF (OBJECT_ID(N'[dbo].[sysutility_mi_cpu_stage_internal]', 'U') IS NULL)
BEGIN
RAISERROR('Creating [dbo].[sysutility_mi_cpu_stage_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_mi_cpu_stage_internal]
(
-- Collected columns
[num_processors] INT NOT NULL DEFAULT -1, -- Collected as Int32, -1 represents unknown
[cpu_name] NVARCHAR(128) NOT NULL DEFAULT N'', -- Collected as String
[cpu_caption] NVARCHAR(128) NOT NULL DEFAULT N'', -- Collected as String
[cpu_family_id] DECIMAL(5,0) NOT NULL DEFAULT -1, -- Collected as UInt16, -1 represents unknown
[cpu_architecture_id] DECIMAL(5,0) NOT NULL DEFAULT -1, -- Collected as UInt16, -1 represents unknown
[cpu_max_clock_speed] DECIMAL(10,0) NOT NULL DEFAULT 0.0, -- Collected as UInt32
[cpu_clock_speed] DECIMAL(10,0) NOT NULL DEFAULT 0.0, -- Collected as UInt32
[l2_cache_size] DECIMAL(10,0) NOT NULL DEFAULT 0.0, -- Collected as UInt32
[l3_cache_size] DECIMAL(10,0) NOT NULL DEFAULT 0.0, -- Collected as UInt32
[instance_processor_usage_start_ticks] DECIMAL(20,0) NOT NULL DEFAULT 0.0, -- Collected as UInt64
[instance_collect_time_start_ticks] DECIMAL(20,0) NOT NULL DEFAULT 0.0, -- Collected as Int64, but should not be negative
[computer_processor_idle_start_ticks] DECIMAL(20,0) NOT NULL DEFAULT 0.0, -- Collected as UInt64
[computer_collect_time_start_ticks] DECIMAL(20,0) NOT NULL DEFAULT 0.0, -- Collected as UInt64
[instance_processor_usage_end_ticks] DECIMAL(20,0) NOT NULL DEFAULT 0.0, -- Collected as UInt64
[instance_collect_time_end_ticks] DECIMAL(20,0) NOT NULL DEFAULT 0.0, -- Collected as Int64, but should not be negative
[computer_processor_idle_end_ticks] DECIMAL(20,0) NOT NULL DEFAULT 0.0, -- Collected as UInt64
[computer_collect_time_end_ticks] DECIMAL(20,0) NOT NULL DEFAULT 0.0, -- Collected as UInt64
-- Computed columns
[server_instance_name] AS (CAST(SERVERPROPERTY('ServerName') AS SYSNAME)),
[virtual_server_name] AS (CAST(SERVERPROPERTY('MachineName') AS SYSNAME)),
[physical_server_name] AS (CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS SYSNAME)),
[instance_processor_usage_percentage] AS
(-- negative elapsed usage indicates instance reboot. use 0 as usage ticks in this case
CAST(
CASE WHEN
-- usage time can be 0 when the instance never got a timeslice (very unlikely)
(0 > instance_processor_usage_end_ticks - instance_processor_usage_start_ticks)
OR (0 >= instance_collect_time_end_ticks - instance_collect_time_start_ticks)
THEN 0.0
ELSE
-- we divide by num_processors since we're getting this info from the process' overall consumption.
-- not the same for the computer-processor information below
((instance_processor_usage_end_ticks - instance_processor_usage_start_ticks)
/ (instance_collect_time_end_ticks - instance_collect_time_start_ticks)
/ num_processors) * 100.0
END
AS REAL)),
[computer_processor_usage_percentage] AS
(-- negative elapsed usage indicates instance reboot. use 0 as usage ticks in this case
CAST(
CASE WHEN
-- idle time can be 0 when the processor is completely saturated
(0 > computer_processor_idle_end_ticks - computer_processor_idle_start_ticks)
OR (0 >= computer_collect_time_end_ticks - computer_collect_time_start_ticks)
THEN 0.0
ELSE
-- 1.0 - PercentProcessorTime because using idle time and want percent utilized time
(1.0 -
((computer_processor_idle_end_ticks - computer_processor_idle_start_ticks)
/ (computer_collect_time_end_ticks - computer_collect_time_start_ticks))) * 100.0
END
AS REAL))
)
END
GO
IF NOT EXISTS (SELECT name FROM [sys].[objects] WHERE object_id = OBJECT_ID(N'[dbo].[sysutility_mi_smo_stage_internal]'))
BEGIN
RAISERROR('Creating [dbo].[sysutility_mi_smo_stage_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_mi_smo_stage_internal]
(
-- Collected columns
[object_type] INT NOT NULL, -- FK reference to sysutility_mi_smo_objects_to_collect_internal.object_type
-- FK is not defined on the table to keep table a light-weight staging table
[urn] NVARCHAR(4000) NOT NULL, -- Collected as String
-- Needs to hold /Server[@Name='']/Database[@Name='']/Filegroup[@Name='']/DataFile[@Name='']
-- where value within '' is SYSNAME, so 600 is enough thus 4000 is plenty
[property_name] NVARCHAR(128) NOT NULL, -- Collected as String, no property should be longer than 80 characters, but we'll be safe
[property_value] SQL_VARIANT NULL, -- Collected as Object
-- Computed columns
[server_instance_name] AS (CAST(SERVERPROPERTY('ServerName') AS SYSNAME)),
[physical_server_name] AS (CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS SYSNAME))
);
END
GO
-------------------------------------------------------------------------
-- Create function: fn_sysutility_mi_get_batch_manifest
-- This function returns the manifest information for the most recent batch collected
-- and is included as a part of the data uploaded from the MI to UCP.
-- The purpose of the manifest is to qualify the consistency of the data uploaded on the UCP.
-- The batch manifest primarily includes:
-- 1. server_instance_name: the server\instance name of the MI
-- 2. batch_time: the batch creation date-time stamp.
-- 3. xx_row_count: row count for each of the table collected/uploaded by the utility T-SQL collection item query
-- Note: a. The server_instance_name & batch_time make the composite key for batch_manifest
-- b. The parameter name is of type string and value is of type sql_variant.
-------------------------------------------------------------------------
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fn_sysutility_mi_get_batch_manifest]') AND type in (N'IF'))
BEGIN
RAISERROR('Dropping [dbo].[fn_sysutility_mi_get_batch_manifest] function', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysutility_mi_get_batch_manifest];
END
GO
RAISERROR('Creating [dbo].[fn_sysutility_mi_get_batch_manifest] function', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_mi_get_batch_manifest]()
RETURNS TABLE
AS
RETURN
(
-- DAC execution statistics row count
SELECT N'dac_packages_row_count' AS parameter_name
, CONVERT(SQL_VARIANT, COUNT(*)) AS parameter_value
FROM [msdb].[dbo].[sysutility_mi_dac_execution_statistics_internal]
UNION ALL
-- MI CPU and memory configurations row count
SELECT N'cpu_memory_configurations_row_count' AS parameter_name
, CONVERT(SQL_VARIANT, COUNT(*)) AS parameter_value
FROM [msdb].[dbo].[sysutility_mi_cpu_stage_internal]
UNION ALL
-- MI volumes row count
SELECT N'volumes_row_count' AS parameter_name
, CONVERT(SQL_VARIANT, COUNT(*)) AS parameter_value
FROM [msdb].[dbo].[sysutility_mi_volumes_stage_internal]
UNION ALL
-- SMO properties row count
SELECT N'smo_properties_row_count' AS parameter_name
, CONVERT(SQL_VARIANT, COUNT(*)) AS parameter_value
FROM [msdb].[dbo].[sysutility_mi_smo_stage_internal]
)
GO
-------------------------------------------------------------------------------
-- Stores the Smo sfc query that is used during data collection
-------------------------------------------------------------------------------
IF (OBJECT_ID(N'[dbo].[sysutility_mi_smo_objects_to_collect_internal]', 'U') IS NULL)
BEGIN
RAISERROR('Creating [dbo].[sysutility_mi_smo_objects_to_collect_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_mi_smo_objects_to_collect_internal]
(
[object_type] INT NOT NULL,
[sfc_query] NVARCHAR(MAX) NOT NULL,
PRIMARY KEY (object_type)
);
END
GO
-------------------------------------------------------------------------------
--Script for filling the smo configurations tables
-------------------------------------------------------------------------------
DELETE FROM [dbo].[sysutility_mi_smo_objects_to_collect_internal]
INSERT INTO [dbo].[sysutility_mi_smo_objects_to_collect_internal] VALUES(1, N'Server');
INSERT INTO [dbo].[sysutility_mi_smo_objects_to_collect_internal] VALUES(2, N'Server/Database');
INSERT INTO [dbo].[sysutility_mi_smo_objects_to_collect_internal] VALUES(3, N'Server/Database[@IsAccessible=1]/LogFile');
-- for SQL10/10.5 file stat dmv support for filestream isn't there, thus we do not collect filestream related
-- file groups and data files. VSTS 351631.
INSERT INTO [dbo].[sysutility_mi_smo_objects_to_collect_internal] VALUES(4, N'Server/Database[@IsAccessible=1]/FileGroup[@IsFileStream=0]');
INSERT INTO [dbo].[sysutility_mi_smo_objects_to_collect_internal] VALUES(5, N'Server/Database[@IsAccessible=1]/FileGroup[@IsFileStream=0]/File');
-------------------------------------------------------------------------------
-- Stores SMO properties to collect
-------------------------------------------------------------------------------
IF (OBJECT_ID(N'[dbo].[sysutility_mi_smo_properties_to_collect_internal]', 'U') IS NULL)
BEGIN
RAISERROR('Creating [dbo].[sysutility_mi_smo_properties_to_collect_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_mi_smo_properties_to_collect_internal]
(
[object_type] INT NOT NULL,
[property_name] NVARCHAR(80) NOT NULL,
PRIMARY KEY (object_type, property_name)
);
ALTER TABLE [dbo].[sysutility_mi_smo_properties_to_collect_internal] WITH CHECK ADD CONSTRAINT [FK_sysutility_mi_smo_properties] FOREIGN KEY([object_type])
REFERENCES [dbo].[sysutility_mi_smo_objects_to_collect_internal] ([object_type])
ON DELETE CASCADE
END
GO
DELETE FROM [dbo].[sysutility_mi_smo_properties_to_collect_internal]
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'AuditLevel');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'BackupDirectory');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'BrowserServiceAccount');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'BrowserStartMode');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'BuildClrVersionString');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'BuildNumber');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'Collation');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'CollationID');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'ComparisonStyle');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'ComputerNamePhysicalNetBIOS');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'DefaultFile');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'DefaultLog');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'Edition');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'EngineEdition');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'ErrorLogPath');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'FilestreamShareName');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'InstallDataDirectory');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'InstallSharedDirectory');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'InstanceName');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'IsCaseSensitive');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'IsClustered');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'IsFullTextInstalled');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'IsSingleUser');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'Language');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'MailProfile');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'MasterDBLogPath');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'MasterDBPath');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'MaxPrecision');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'Name');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'NamedPipesEnabled');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'NetName');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'NumberOfLogFiles');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'OSVersion');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'PerfMonMode');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'PhysicalMemory');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'Platform');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'Processors');
-- note for this 'ProcessorUsage' property this is just a placeholder, we in fact collect its value
-- by ourselves instead of relying on SMO.Server.ProcessorUsage property for two reasons
-- 1) our collection mechanism is more accurate because we're doing averaging over
-- our entire collection cycle versus, SMO property value was very instantaneous.
-- 2) this SMO property isn't available downlevel (before 10.5)
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'ProcessorUsage');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'Product');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'ProductLevel');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'ResourceVersionString');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'RootDirectory');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'ServerType');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'ServiceAccount');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'ServiceInstanceId');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'ServiceName');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'ServiceStartMode');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'SqlCharSet');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'SqlCharSetName');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'SqlDomainGroup');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'SqlSortOrder');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'SqlSortOrderName');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'Status');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'TapeLoadWaitTime');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'TcpEnabled');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'VersionMajor');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'VersionMinor');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(1, N'VersionString');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(2, N'CreateDate');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(2, N'Collation');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(2, N'CompatibilityLevel');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(2, N'EncryptionEnabled');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(2, N'ID');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(2, N'Name');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(2, N'RecoveryModel');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(2, N'Trustworthy');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(3, N'FileName');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(3, N'Growth');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(3, N'GrowthType');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(3, N'ID');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(3, N'MaxSize');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(3, N'Name');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(3, N'Size');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(3, N'UsedSpace');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(4, N'ID');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(4, N'Name');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(5, N'FileName');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(5, N'Growth');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(5, N'GrowthType');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(5, N'ID');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(5, N'MaxSize');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(5, N'Name');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(5, N'Size');
INSERT INTO [dbo].[sysutility_mi_smo_properties_to_collect_internal] VALUES(5, N'UsedSpace');
GO
-----------------------------------------------------------------------
-- Script for creating Utility Collection sets and Collection set items.
-----------------------------------------------------------------------
DECLARE @collection_set_number INT = 0 ;
DECLARE @running_state BIT;
DECLARE @collection_set_name NVARCHAR(128);
DECLARE @description NVARCHAR(4000);
DECLARE @collection_set_uid uniqueidentifier;
DECLARE @collection_mode smallint;
DECLARE @schedule_name sysname;
DECLARE @days_until_expiration smallint;
DECLARE @name_id int;
DECLARE @description_id int;
DECLARE @collection_set_id INT
DECLARE @proxy_id int = NULL;
SET @name_id = 14716;
SET @description_id = 14715;
SET @collection_set_uid = N'ABA37A22-8039-48C6-8F8F-39BFE0A195DF';
SET @collection_mode = 1; -- Non-cached
SET @schedule_name = N''; -- Non-scheduled. The Utility collection runs on-demand through the Utility-owned job.
DECLARE @frequency int = 900; -- Collection is on demand, this value is ignored
SET @days_until_expiration = 1;
SET @description = FORMATMESSAGE(@description_id);
SET @collection_set_name = ISNULL (FORMATMESSAGE(@name_id), 'Utility Information');
-- Unlike the MDW system collection sets, we don't need to retain any customized schedule added by the user. The
-- Utility collection set is not scheduled and we want it to stay that way. To simplify this code, we just drop
-- the collection set if it exists, then recreate it.
IF EXISTS (SELECT * FROM dbo.syscollector_collection_sets_internal WHERE collection_set_uid = @collection_set_uid)
BEGIN
RAISERROR ('Deleting collection set "%s"...', 0, 1, @collection_set_name) WITH NOWAIT;
-- Get the collection set's collection set ID and save off the current proxy ID. If the collection set was
-- configured to run under a proxy account, this is the one user-specified attribute that we need to preserve
-- when we recreate it. If the collection set has not been configured, proxy_id will be NULL. When we pass
-- NULL to sp_syscollector_create_collection_set when recreating the collection set, a NULL value for the
-- @proxy_id parameter also means "don't use a proxy".
SELECT
@collection_set_id = collection_set_id,
@proxy_id = proxy_id
FROM syscollector_collection_sets
WHERE collection_set_uid = @collection_set_uid;
-- Temporarily clear the is_system flag so that we can modify the collection set definition
UPDATE syscollector_collection_sets
SET is_system = 0
WHERE collection_set_id = @collection_set_id
EXEC sp_syscollector_delete_collection_set @collection_set_id = @collection_set_id;
END
RAISERROR ('Creating system Collection Set "%s"...', 0, 1, @collection_set_name) WITH NOWAIT;
EXEC dbo.sp_syscollector_create_collection_set
@collection_set_uid = @collection_set_uid,
@name = @collection_set_name,
@schedule_name = @schedule_name,
@collection_mode = @collection_mode,
@days_until_expiration = @days_until_expiration,
@description = @description,
@logging_level = 0,
@proxy_id = @proxy_id,
@collection_set_id = @collection_set_id OUTPUT;
IF(FORMATMESSAGE(@name_id) IS NOT NULL)
BEGIN
-- for localization of collection set name and description
UPDATE syscollector_collection_sets_internal
SET name_id = @name_id, description_id = @description_id
WHERE collection_set_uid = @collection_set_uid;
END
DECLARE @collector_type_uid_3 UNIQUEIDENTIFIER
SELECT @collector_type_uid_3 = collector_type_uid
FROM [dbo].[syscollector_collector_types]
WHERE name = N'Generic T-SQL Query Collector Type';
DECLARE @collection_item_loc_name NVARCHAR(128);
DECLARE @collection_item_enu_name NVARCHAR(128);
DECLARE @collection_item_id int;
SET @name_id = 14718;
SET @collection_item_enu_name = 'Utility Information - Managed Instance';
SET @collection_item_loc_name = ISNULL (FORMATMESSAGE(@name_id), @collection_item_enu_name);
DECLARE @parameters xml;
SELECT @parameters = convert(xml, N'<ns:TSQLQueryCollector xmlns:ns="DataCollectorType">
<Query>
<Value>
EXEC [msdb].[dbo].[sp_sysutility_mi_get_dac_execution_statistics_internal];
</Value><OutputTable>sysutility_ucp_dac_collected_execution_statistics_internal</OutputTable>
</Query>
<Query>
<Value>
-- Check for the existance of the temp table. If it is there, then the Utility is
-- set up correctly. If it is not there, do not fail the upload. This handles the
-- case when a user might run the collection set out-of-band from the Utility.
-- The data may not be staged, but no sporratic errors should occur
DECLARE @batch_time datetimeoffset(7) = SYSDATETIMEOFFSET()
IF OBJECT_ID (''[tempdb].[dbo].[sysutility_batch_time_internal]'') IS NOT NULL
BEGIN
SELECT @batch_time = latest_batch_time FROM tempdb.dbo.sysutility_batch_time_internal
END
SELECT
[server_instance_name],
CAST(clustered_check.is_clustered_server AS SMALLINT) AS [is_clustered_server],
[virtual_server_name],
[physical_server_name],
[num_processors],
[computer_processor_usage_percentage] AS [server_processor_usage],
[instance_processor_usage_percentage] AS [instance_processor_usage],
[cpu_name],
[cpu_caption],
[msdb].[dbo].[fn_sysutility_mi_get_cpu_family_name](cpu_family_id) AS [cpu_family],
[msdb].[dbo].[fn_sysutility_mi_get_cpu_architecture_name](cpu_architecture_id) AS [cpu_architecture],
[cpu_max_clock_speed],
[cpu_clock_speed],
[l2_cache_size],
[l3_cache_size],
@batch_time AS [batch_time]
FROM [msdb].[dbo].[sysutility_mi_cpu_stage_internal],
(SELECT TOP 1 CAST (CASE WHEN COUNT(*) = 0 THEN 0 ELSE 1 END AS bit) AS is_clustered_server
FROM msdb.sys.dm_os_cluster_nodes
WHERE NodeName = SERVERPROPERTY(''ComputerNamePhysicalNetBIOS'')) AS clustered_check
</Value><OutputTable>sysutility_ucp_cpu_memory_configurations_internal</OutputTable>
</Query>
<Query>
<Value>
-- Check for the existance of the temp table. If it is there, then the Utility is
-- set up correctly. If it is not there, do not fail the upload. This handles the
-- case when a user might run the collection set out-of-band from the Utility.
-- The data may not be staged, but no sporratic errors should occur
DECLARE @batch_time datetimeoffset(7) = SYSDATETIMEOFFSET()
IF OBJECT_ID (''[tempdb].[dbo].[sysutility_batch_time_internal]'') IS NOT NULL
BEGIN
SELECT @batch_time = latest_batch_time FROM tempdb.dbo.sysutility_batch_time_internal
END
SELECT
[volume_device_id],
[volume_name],
CAST([capacity_mb] AS REAL) AS [total_space_available],
CAST([free_space_mb] AS REAL) AS [free_space],
[virtual_server_name],
[physical_server_name],
[server_instance_name],
@batch_time AS [batch_time]
FROM [msdb].[dbo].[sysutility_mi_volumes_stage_internal]
</Value>
<OutputTable>sysutility_ucp_volumes_internal</OutputTable>
</Query>
<Query>
<Value>
-- Check for the existance of the temp table. If it is there, then the Utility is
-- set up correctly. If it is not there, do not fail the upload. This handles the
-- case when a user might run the collection set out-of-band from the Utility.
-- The data may not be staged, but no sporratic errors should occur
DECLARE @batch_time datetimeoffset(7) = SYSDATETIMEOFFSET()
IF OBJECT_ID (''[tempdb].[dbo].[sysutility_batch_time_internal]'') IS NOT NULL
BEGIN
SELECT @batch_time = latest_batch_time FROM tempdb.dbo.sysutility_batch_time_internal
END
SELECT
smo.[physical_server_name],
smo.[server_instance_name],
[object_type],
[urn],
[property_name],
-- DC (SSIS, really) does not support sql_variant. It will implicitly convert all variant columns to nvarchar(256),
-- which can cause data loss. To avoid this we explicitly convert to nvarchar(4000) so that nothing gets truncated.
-- On the UCP, we reverse this conversion in sp_copy_live_table_data_into_cache_tables. In order to round-trip the
-- data through nvarchar successfully, we must use the same language-independent conversion style on MI and UCP. We
-- use the shared fn_sysutility_get_culture_invariant_conversion_style_internal function to get a consistent
-- language-independent conversion style for each property data type. (References: VSTS 361531, 359504, 12967)
CONVERT
(
nvarchar(4000),
CASE [property_name]
WHEN N''ProcessorUsage'' -- Hijack the ProcessorUsage property and insert our own value
THEN CAST(cpu.[instance_processor_usage_percentage] AS INT) -- loss of decimal places
ELSE [property_value]
END,
msdb.dbo.fn_sysutility_get_culture_invariant_conversion_style_internal(CONVERT (varchar(30), SQL_VARIANT_PROPERTY (property_value, ''BaseType'')))
) AS [property_value],
@batch_time AS [batch_time]
FROM [msdb].[dbo].[sysutility_mi_smo_stage_internal] AS smo
INNER JOIN [msdb].[dbo].[sysutility_mi_cpu_stage_internal] AS cpu
ON smo.[server_instance_name] = cpu.[server_instance_name]
</Value><OutputTable>sysutility_ucp_smo_properties_internal</OutputTable>
</Query>
<!-- Query to collect/upload the batch manifest -->
<Query>
<Value>
-- Check for the existance of the temp table. If it is there, then the Utility is
-- set up correctly. If it is not there, do not fail the upload. This handles the
-- case when a user might run the collection set out-of-band from the Utility.
-- The data may not be staged, but no sporratic errors should occur
DECLARE @batch_time datetimeoffset(7) = SYSDATETIMEOFFSET()
IF OBJECT_ID (''[tempdb].[dbo].[sysutility_batch_time_internal]'') IS NOT NULL
BEGIN
SELECT @batch_time = latest_batch_time FROM tempdb.dbo.sysutility_batch_time_internal
END
SELECT CONVERT(SYSNAME, SERVERPROPERTY(N''ServerName'')) AS [server_instance_name],
@batch_time AS [batch_time],
bm.parameter_name,
bm.parameter_value
FROM [msdb].[dbo].[fn_sysutility_mi_get_batch_manifest]() bm
</Value>
<OutputTable>sysutility_ucp_batch_manifests_internal</OutputTable>
</Query>
</ns:TSQLQueryCollector>');
SET @collection_item_id = NULL;
SELECT @collection_item_id = collection_item_id
FROM syscollector_collection_items_internal
WHERE collection_set_id = @collection_set_id
AND (name = @collection_item_loc_name OR name = @collection_item_enu_name);
IF (@collection_item_id IS NOT NULL)
BEGIN
RAISERROR ('Updating Collection Item "%s"...', 0, 1, @collection_item_loc_name);
EXEC dbo.sp_syscollector_update_collection_item
@collection_item_id = @collection_item_id,
@new_name = @collection_item_loc_name,
@frequency = @frequency,
@parameters = @parameters;
END
ELSE
BEGIN
RAISERROR ('Creating Collection Item "%s"...', 0, 1, @collection_item_loc_name);
EXEC dbo.sp_syscollector_create_collection_item
@collection_set_id = @collection_set_id,
@collector_type_uid = N'302E93D1-3424-4BE7-AA8E-84813ECF2419',
@name = @collection_item_loc_name,
@parameters = @parameters,
@frequency = @frequency,
@collection_item_id = @collection_item_id output;
END;
IF(FORMATMESSAGE(@name_id) IS NOT NULL)
BEGIN
-- for localization of collection item name
UPDATE syscollector_collection_items_internal
SET name_id = @name_id
WHERE collection_item_id = @collection_item_id;
END
-- Turn the is_system flag on so users can't change the definition of this collection set
UPDATE syscollector_collection_sets
SET is_system = 1
WHERE collection_set_id = @collection_set_id
GO
----------------------------------------------------------------
-- An SP to get whether the instance is already running DC
-- OR not
----------------------------------------------------------------
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fn_sysutility_mi_get_data_collector_status]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
BEGIN
RAISERROR('Dropping [dbo].[fn_sysutility_mi_get_data_collector_status] procedure', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysutility_mi_get_data_collector_status];
END
GO
RAISERROR('Creating [dbo].[fn_sysutility_mi_get_data_collector_status] procedure', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_mi_get_data_collector_status]()
RETURNS BIT
AS
BEGIN
RETURN
(
SELECT CAST (ISNULL (parameter_value, 0) AS bit)
FROM [msdb].[dbo].[syscollector_config_store_internal]
WHERE parameter_name = 'CollectorEnabled'
);
END
GO
--------------------------------------------------------
-- Utility collect and upload procedures and functions
--------------------------------------------------------
-------------------------------------------------------------------------------
-- Upload the collected data to the utility control point.
--
-- Specifics:
-- The Utility uses the data collector to upload data to the UCP. The
-- collection set corresponding to the Utility is set to on-demand mode.
-- The Utility directs the data collector to run the collect and upload cycle
-- through a Utility-owned job. The Utility-owned job first stages data,
-- and in the final job step calls this procedure to direct DC to pick up
-- the staged data and upload it to the UCP.
-------------------------------------------------------------------------------
IF OBJECT_ID ('[dbo].[sp_sysutility_mi_upload]') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_mi_upload]', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_upload]
END;
RAISERROR ('Creating procedure [dbo].[sp_sysutility_mi_upload]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_upload]
WITH EXECUTE AS OWNER
AS
BEGIN
SET NOCOUNT ON;
-- Check if the instance is enrolled
IF ( 0 = (select [dbo].[fn_sysutility_ucp_get_instance_is_mi]()) )
BEGIN
RAISERROR(37006, -1, -1)
RETURN(1)
END
-- Check if Data Collector is enabled
-- The following sproc will throw the correct error DC is disabled
DECLARE @return_code INT;
EXEC @return_code = [dbo].[sp_syscollector_verify_collector_state] @desired_state = 1
IF (@return_code <> 0)
RETURN (1)
DECLARE @poll_delay_hh_mm_ss char(8) = '00:00:10';
DECLARE @start_delay_hh_mm_ss char(8) = '00:00:10';
DECLARE @start_time datetime2 = SYSUTCDATETIME();
DECLARE @elapsed_time_ss INT
DECLARE @collection_set_uid UNIQUEIDENTIFIER = N'ABA37A22-8039-48C6-8F8F-39BFE0A195DF';
DECLARE @collection_set_id INT = (SELECT collection_set_id FROM [dbo].[syscollector_collection_sets_internal]
WHERE collection_set_uid = @collection_set_uid);
DECLARE @is_upload_running INT;
DECLARE @is_collection_running INT;
-- If the collection set is running for some reason, wait for it
-- to complete before instructing it to upload again.
-- Assume that the collection is running before the loop starts
SET @is_upload_running = 1;
SET @is_collection_running = 1;
-- Wait for the collection set to finish its previous execution
WHILE(1 = @is_collection_running OR 1 = @is_upload_running)
BEGIN
-- Reset the while loop variables. The sp will not update the values, if the collection
-- is currently not running
SET @is_upload_running = NULL;
SET @is_collection_running = NULL;
EXEC @return_code = [dbo].[sp_syscollector_get_collection_set_execution_status]
@collection_set_id = @collection_set_id,
@is_collection_running = @is_collection_running OUTPUT,
@is_upload_running = @is_upload_running OUTPUT
IF (@@ERROR <> 0 OR @return_code <> 0) GOTO QuitWithError;
-- Check to see if the collection is running before calling wait.
-- It is more likely that it is not running, thus it is not optimal to wait.
IF (1 = @is_collection_running OR 1 = @is_upload_running)
BEGIN
SET @elapsed_time_ss = DATEDIFF(second, @start_time, SYSUTCDATETIME())
RAISERROR ('Waiting for collection set to finish its previous run. Total seconds spent waiting : %i', 0, 1, @elapsed_time_ss) WITH NOWAIT;
WAITFOR DELAY @poll_delay_hh_mm_ss
END
END
-- Grab the time before running the collection. Use local time because later this value is used
-- to find failures in the DC logs, which use local time.
DECLARE @run_start_time datetime = SYSDATETIME();
-- Start the collect and upload by invoking the run command
RAISERROR ('Starting collection set.', 0, 1) WITH NOWAIT;
EXEC @return_code = [msdb].[dbo].[sp_syscollector_run_collection_set] @collection_set_id = @collection_set_id
IF (@@ERROR <> 0 OR @return_code <> 0) GOTO QuitWithError;
-- Allow the collection set to start
RAISERROR ('Waiting for the collection set to kick off jobs.', 0, 1) WITH NOWAIT;
WAITFOR DELAY @start_delay_hh_mm_ss
-- Assume that the collection is running before the loop starts
SET @is_upload_running = 1;
SET @is_collection_running = 1;
-- Wait for the collection set to finish it's previous execution
WHILE(1 = @is_collection_running OR 1 = @is_upload_running)
BEGIN
-- Reset the while loop variables. The sp will not update the values, if the collection
-- is currently not running
SET @is_upload_running = NULL;
SET @is_collection_running = NULL;
-- Go ahead and wait on entry to the loop because it takes a
-- while for the collection set to finish collection
SET @elapsed_time_ss = DATEDIFF(second, @start_time, SYSUTCDATETIME())
RAISERROR ('Waiting for collection set to finish its previous run. Total seconds spent waiting : %i', 0, 1, @elapsed_time_ss) WITH NOWAIT;
WAITFOR DELAY @poll_delay_hh_mm_ss
EXEC @return_code = [dbo].[sp_syscollector_get_collection_set_execution_status]
@collection_set_id = @collection_set_id,
@is_collection_running = @is_collection_running OUTPUT,
@is_upload_running = @is_upload_running OUTPUT
IF (@@ERROR <> 0 OR @return_code <> 0) GOTO QuitWithError;
END
DECLARE @status_failure smallint = 2
DECLARE @last_reported_status smallint = NULL
-- Check if the collect/upload failed anytime after the call to run
-- This is not precise in finding our exact run, but most of the time it will find our run
-- What we really need to know is if the collect/upload failed
-- There is a possibility that there are false positives (report failure, when our call to run passed)
-- However, we are willing to risk it for simplicity.
SELECT TOP 1 @last_reported_status = status
FROM msdb.dbo.syscollector_execution_log_internal
WHERE collection_set_id = @collection_set_id
AND parent_log_id IS NULL
AND finish_time IS NOT NULL
AND start_time >= @run_start_time
ORDER BY finish_time DESC
IF (@last_reported_status = @status_failure)
BEGIN
RAISERROR(37007, -1, -1)
RETURN(1) -- Failure
END
Return(0);
QuitWithError:
RAISERROR ('An error occurred during execution.', 0, 1) WITH NOWAIT;
RETURN (1);
END
GO
IF (OBJECT_ID(N'[dbo].[fn_sysutility_mi_get_collect_script]') IS NOT NULL)
BEGIN
RAISERROR('Dropping [dbo].[fn_sysutility_mi_get_collect_script] function', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysutility_mi_get_collect_script];
END
GO
RAISERROR('Creating [dbo].[fn_sysutility_mi_get_collect_script] function', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_mi_get_collect_script]()
RETURNS NVARCHAR(MAX)
AS
BEGIN
RETURN '[Void] [System.Reflection.Assembly]::LoadWithPartialName("System.Data")
[Void] [System.Reflection.Assembly]::LoadWithPartialName("System.Diagnostics")
[Void] [System.Reflection.Assembly]::LoadWithPartialName("System.Collections")
###############################################################################
# Powershell settings
###############################################################################
# Generate an error if attempt to access a nonexisting variable
Set-PsDebug -Strict
# Global settings for what to do on a error, warning, or verbose call
# Change these settings to change how this script writes output in the agent logs
# Settings also affects how SQL Agent reports success or failure in the script
# Options are:
# Continue - Continue processing and notify the user
# - Agent reaction: step will report success, and
# log will include message
# Inquire - Stop processing and ask the user how it should proceed
# - Agent reaction: step fails with "cannot invoke this function"
# the Agent PS provider does not implement this
# SilentlyContinue - Continue processing without notifying the user
# - Agent reaction: will not fail step
# and will not log any message
# Stop - Stop processing when an action occurs
# - Agent reaction: step will fail with message in log
$VerbosePreference = "SilentlyContinue"
$WarningPreference = "Continue"
$ErrorActionPreference = "Stop"
###############################################################################
# Global Variables
###############################################################################
# The following line uses SQL Agent tokens to set the server name
# ESCAPE_SQUOTE(SRVR) with a $ sign in front is a special token to SQL Agent
# When the job is run, SQL Agent will expand the string to the server name
# Use single quotes so that PS considers the string a literal and will not
# try to expand the $ reference and the script will not fail in a test environment
$serverName = ''$(ESCAPE_SQUOTE(SRVR))''
# Currently the best way to tell if the script is running in Agent
# is to check if the console is not the ConsoleHost. The Powershell
# subsystem for Agent has no console and thus writing to the host directly
# does not show up in the Agent logs.
$isNotConsole = ($host.Name -ne "ConsoleHost")
$connection = $null
$transaction = $null
$isVistaOrXPSp2OrHigher = $null
$sleepTimeoutSeconds = 5
$directoryNameToDeviceId=$null
$cpuStageTableName = "[msdb].[dbo].[sysutility_mi_cpu_stage_internal]"
$cpuStageDataTable = $null
$cpuNumProcessorsColumnName = "num_processors"
$cpuNameColumnName = "cpu_name"
$cpuCaptionColumnName = "cpu_caption"
$cpuFamilyIdColumnName = "cpu_family_id"
$cpuArchitectureIdColumnName = "cpu_architecture_id"
$cpuMaxClockSpeedColumnName = "cpu_max_clock_speed"
$cpuClockSpeedColumnName = "cpu_clock_speed"
$cpuL2CacheSizeColumnName = "l2_cache_size"
$cpuL3CacheSizeColumnName = "l3_cache_size"
# Start of collection column names
$cpuInstanceProcessorUsageStartTicks = "instance_processor_usage_start_ticks"
$cpuInstanceCollectTimeStartTicks = "instance_collect_time_start_ticks"
$cpuComputerProcessorIdleStartTicks = "computer_processor_idle_start_ticks"
$cpuComputerCollectTimeStartTicks = "computer_collect_time_start_ticks"
# End of collection column names
$cpuInstanceProcessorUsageEndTicks = "instance_processor_usage_end_ticks"
$cpuInstanceCollectTimeEndTicks = "instance_collect_time_end_ticks"
$cpuComputerProcessorIdleEndTicks = "computer_processor_idle_end_ticks"
$cpuComputerCollectTimeEndTicks = "computer_collect_time_end_ticks"
$volumeStageTableName = "[msdb].[dbo].[sysutility_mi_volumes_stage_internal]"
$volumeStageDataTable = $null
$volumeDeviceIdColumnName = "volume_device_id"
$volumeNameColumnName = "volume_name"
$volumeCapacityColumnName = "capacity_mb"
$volumeFreeSpaceColumnName = "free_space_mb"
$smoStageTableName = "[msdb].[dbo].[sysutility_mi_smo_stage_internal]"
$smoStageDataTable = $null
$smoTypeColumnName = "object_type"
$smoUrnColumnName = "urn"
$smoPropertyNameColumnName = "property_name"
$smoPropertyValueColumnName = "property_value"
###############################################################################
# Functions that help with handling output to SQL Agent
#
# Sql Agent PS provider does not write output to the log from
# the warnings, errors, and verbose Write cmdlets. The following
# functions wrap these cmdlets for execution as an agent job step.
###############################################################################
# This function is a helper function throws an exception if the passed in object
# is null or empty. The intent is to mimic the PowerShell version 2.0 parameter
# validation function with the same name. The paramter validation is available
# in 2.0 or higher, but this script can run in 1.0 or 2.0 runtime environment.
function ValidateNotNullOrEmpty($object)
{
if(($object -eq $null) -or ($object -eq ""))
{
throw "The argument is null or empty."
}
}
# This function helps control control flow for the agent step context
# When running within agent, there are different semantics for writing
# errors, warnings, and messages. In addition, when running inside an
# agent step, the script will automatically collect and stage data.
# However, if the script is loaded in a PS environment outside of
# agent, the script will not automatically start to collect and stage data
#
# Returns True if the script is run inside an agent step
# False if the script is run outside an agent step
function Get-IsAgentStep
{
$global:isNotConsole
}
function Write-AgentLog([String] $prefix, [String] $printString, [String] $preference)
{
if((Get-IsAgentStep) -and ($preference -ne "SilentlyContinue"))
{
[Console]::Error.WriteLine($prefix + $printString)
}
}
function Get-PrintString ($object)
{
ValidateNotNullOrEmpty $object
$date = Get-Date -DisplayHint Time
$printString = $date.ToString() + " : " + $object.ToString()
$printString
}
function Write-ScriptVerbose ($object)
{
$printString = Get-PrintString $object
Write-AgentLog "VERBOSE : " $printString $VerbosePreference
Write-Verbose $printString
}
function Write-ScriptWarning ($object)
{
$printString = Get-PrintString $object
Write-AgentLog "WARNING : " $printString $WarningPreference
Write-Warning $printString
}
function Write-ScriptError ($object)
{
$printString = Get-PrintString $object
Write-AgentLog "ERROR : " $printString $ErrorActionPreference
Write-Error $printString
}
function Resolve-Error ($ErrorRecord=$Error[0])
{
$errorString = $ErrorRecord | Format-List * -Force | Out-String
Write-ScriptWarning $errorString
$errorString = $ErrorRecord.InvocationInfo | Format-List * | Out-String
Write-ScriptWarning $errorString
$Exception = $ErrorRecord.Exception
# Print the entire stack of exceptions
for ($i = 0; $Exception; $i++, ($Exception = $Exception.InnerException))
{ Write-ScriptWarning ("$i" * 80)
$errorString = $Exception | Format-List * -Force | Out-String
Write-ScriptWarning $errorString
}
}
###############################################################################
# Connection Functions help to send queries to and manage the connection
# to the server .
###############################################################################
function Get-Connection
{
if($global:serverName.Contains(''ESCAPE_SQUOTE(SRVR)''))
{
throw "The global variable serverName has not been set."
}
if($global:connection -eq $null)
{
Write-ScriptVerbose "Opening connection to $global:serverName"
$connString="Application Name=SQL Server Utility Managed Instance;Server=$global:serverName;Database=msdb;Trusted_Connection=True;"
$global:connection = New-Object System.Data.SqlClient.SqlConnection
$global:connection.ConnectionString = $connString
[Void]$global:connection.Open()
Write-ScriptVerbose "Opened connection with connection string:`n $connString"
}
$global:connection
}
function Remove-Connection
{
if($global:connection -ne $null)
{
$dataSource=$global:connection.DataSource
Write-ScriptVerbose "Closing and disposing connection to $dataSource"
[Void]$global:connection.Close()
[Void]$global:connection.Dispose()
Write-ScriptVerbose "Connection is closed and disposed"
}
$global:connection = $null
}
function Invoke-BeginTransaction([string] $tranName)
{
Write-ScriptVerbose "Opening transaction"
$sqlConnection = Get-Connection
$global:transaction = $sqlConnection.BeginTransaction($tranName)
}
function Invoke-CommitTransaction
{
if($global:transaction -ne $null)
{
Write-ScriptVerbose "Committing transaction"
$global:transaction.Commit()
$global:transaction.Dispose()
$global:transaction = $null
}
}
function Invoke-RollbackTransaction
{
if($global:transaction -ne $null)
{
Write-ScriptVerbose "Rolling back transaction"
$global:transaction.Rollback()
$global:transaction.Dispose()
$global:transaction = $null
}
}
function Invoke-SubmitSqlCommandNonQuery([string] $query)
{
ValidateNotNullOrEmpty $query
Write-ScriptVerbose "Submitting as NonQuery : $query"
$TsqlCommand = New-Object System.Data.SqlClient.SqlCommand;
$TsqlCommand.CommandText = $query
$TsqlCommand.CommandType = "Text";
$TsqlCommand.Transaction = $global:transaction
$TsqlCommand.Connection = Get-Connection
$TsqlCommand.CommandTimeout = 0
[Void] $TsqlCommand.ExecuteNonQuery()
}
function Get-SqlDataTable([string] $query)
{
ValidateNotNullOrEmpty $query
Write-ScriptVerbose "Requesting data table for : $query"
$sqlConnection = Get-Connection
$dataAdapter = New-Object System.Data.SqlClient.SqlDataAdapter($query, $sqlConnection)
$dataTable = New-Object System.Data.DataTable
$rowsFilled = $dataAdapter.Fill($dataTable)
Write-ScriptVerbose "Query added $rowsFilled rows to the data table"
# return the data table. We need to wrap the variable because PS will
# return data rows otherwise.
return @(,($dataTable))
}
function Invoke-BulkCopyCommand([System.Data.DataTable] $dataTableData)
{
ValidateNotNullOrEmpty $dataTableData
$opt = [System.Data.SqlClient.SqlBulkCopyOptions]
# Obtain a TableLock
# But do not (use) Default (options), KeepIdentity, CheckConstraints, KeepNulls
# FireTriggers, UseInternalTransaction
$bulkOptions = $opt::none -bxor ("TableLock" -as $opt)
$tabName=$dataTableData.TableName
Write-ScriptVerbose "Bulk copying data table : $tabName"
$sqlConnection = Get-Connection
$bulkCopy = new-object Data.SqlClient.SqlBulkCopy $sqlConnection, $bulkOptions, $global:transaction
$bulkCopy.DestinationTableName = $dataTableData.TableName
#Map the columns so that the computed columns are skipped in the upload
foreach($col in $dataTableData.Columns)
{
[Void] $bulkCopy.ColumnMappings.Add($col.ColumnName,
$col.ColumnName)
}
[Void] $bulkCopy.WriteToServer($dataTableData)
}
###############################################################################
# Short Helper Functions
###############################################################################
function Get-DefaultIfNull($object, $default)
{
if($object -eq $null)
{
$default
}
else
{
$object
}
}
function Get-StringDefaultIfNull([String] $object)
{
Get-DefaultIfNull $object ""
}
function Get-NumericDefaultIfNull($object)
{
Get-DefaultIfNull $object 0
}
function Get-ProcessId
{
$result = Get-SqlDataTable "SELECT SERVERPROPERTY(''ProcessID'') AS ProcessId" | %{ $_.Rows }
$result.ProcessId
}
function Get-IsWmiVolumeQueryAvailable
{
if($global:isVistaOrXPSp2OrHigher -eq $null)
{
$osVersion = [System.Environment]::OsVersion.Version
$global:isVistaOrXPSp2OrHigher = ($osVersion.Major -ge 6 -or ($osVersion.Major -ge 5 -and $osVersion.Minor -ge 2))
}
Write-ScriptVerbose "This computer is Vista or XP Sp2 or higher value is $global:isVistaOrXPSp2OrHigher"
$global:isVistaOrXPSp2OrHigher
}
# Trims the volume name to <drive_letter>: format.
# Reason: Data collection using WMI on different OS returns diffrent volume formats
# E.g. Win32_LogicalDisk on WIN2K3 returns c: and Win32_Volume on WIN2K8 returns c:\
function Get-FormattedVolumeName([String] $volumeName)
{
[String] $volumeName = Get-StringDefaultIfNull $volumeName
Write-ScriptVerbose "Formatting volume name $volumeName"
if($volumeName.EndsWith("\"))
{
$volumeName = $volumeName.SubString(0,$volumeName.Length - 1)
}
Write-ScriptVerbose "Formatted volume name to $volumeName"
$volumeName
}
function Get-MountPointDictionary()
{
if($global:directoryNameToDeviceId -eq $null)
{
$global:directoryNameToDeviceId=@{}
(Get-Wmiobject Win32_MountPoint) |
%{ $directory=$_.Directory.Replace("Win32_Directory.Name=", "").Replace("`"", "").Replace("\\", "\")
$deviceId=$_.Volume.Replace("Win32_Volume.DeviceID=`"", "").Replace("`"", "").Replace("\\", "\")
$global:directoryNameToDeviceId[$directory]=$deviceId
}
}
return $global:directoryNameToDeviceId
}
# The following function returns a directory name that maps to a volume device
# based on longest match. It is not exact because a file can have a long
# convoluted path that pass through many mount point references
# However, it will find the most common use case for mount points
function Get-MountPointName([String] $fileName)
{
[String] $fileName = Get-StringDefaultIfNull $fileName
$longestMatch = ""
$dict = Get-MountPointDictionary
foreach($directory in $dict.Keys)
{
if($fileName.StartsWith($directory, [System.StringComparison]::OrdinalIgnoreCase))
{
if($directory.Length -gt $longestMatch.Length)
{
$longestMatch = $directory
}
}
}
return $longestMatch
}
function Get-DeviceIdFromMountPointName([String] $mountPointDirectory)
{
[String] $mountPointDirectory = Get-StringDefaultIfNull $mountPointDirectory
$dict = Get-MountPointDictionary
$dict[$mountPointDirectory]
}
function Get-MegabytesFromBytes ([Uint64] $bytes)
{
[Uint64] $bytes = Get-NumericDefaultIfNull $bytes
Write-ScriptVerbose "Converting $bytes bytes to megabytes"
$oneMB = 1048576
[UInt64] ($bytes / $oneMB) # No fractional MBs
}
function Get-ShouldCollectCpu
{
if( ($global:cpuStageDataTable -eq $null) -or ($global:cpuStageDataTable.Rows.Count -eq 0))
{
Write-ScriptVerbose "The cpu staging table is null or empty. Get-ShouldCollectCpu returning true"
# return True and exit early
return $true
}
else
{
$dataRow = $global:cpuStageDataTable.Rows[0]
# return the value of the disjunction
$dataRow[$cpuInstanceProcessorUsageStartTicks] -eq 0 -or
$dataRow[$cpuInstanceCollectTimeStartTicks] -eq 0 -or
$dataRow[$cpuComputerProcessorIdleStartTicks] -eq 0 -or
$dataRow[$cpuComputerCollectTimeStartTicks] -eq 0
}
}
###############################################################################
# Staging Functions that construct DataTables based on the different types of
# data collection
###############################################################################
function Add-StageCpuRow
{
param ([Int32] $numProcessors, [String] $cpuName, [String] $cpuCaption, [UInt16] $cpuFamily,
[UInt16] $architecture, [UInt32] $cpuMaxClockSpeed, [UInt32] $clockSpeed,
[UInt32] $l2CacheSize, [UInt32] $l3CacheSize,
[UInt64] $instanceProcessorUsage, [Int64] $instanceCollectTime,
[UInt64] $computerIdleTime, [UInt64] $computerCollectTime)
begin
{
# This function update the Cpu table in-place by
# first querying the server for the previous collection
# information
if($global:cpuStageDataTable -eq $null)
{
$query = "SELECT
$cpuNumProcessorsColumnName,
$cpuNameColumnName,
$cpuCaptionColumnName,
$cpuFamilyIdColumnName,
$cpuArchitectureIdColumnName,
$cpuMaxClockSpeedColumnName,
$cpuClockSpeedColumnName,
$cpuL2CacheSizeColumnName,
$cpuL3CacheSizeColumnName,
$cpuInstanceProcessorUsageStartTicks,
$cpuInstanceCollectTimeStartTicks,
$cpuComputerProcessorIdleStartTicks,
$cpuComputerCollectTimeStartTicks,
$cpuInstanceProcessorUsageEndTicks,
$cpuInstanceCollectTimeEndTicks,
$cpuComputerProcessorIdleEndTicks,
$cpuComputerCollectTimeEndTicks
FROM $global:cpuStageTableName"
$global:cpuStageDataTable = Get-SqlDataTable $query
# If the data table is null, then there is no
# data on the server and the table needs to be initialized
if($global:cpuStageDataTable -eq $null)
{
Write-ScriptVerbose "Database returned no rows for cpu table. Creating table definition"
$global:cpuStageDataTable = New-Object System.Data.DataTable ($global:cpuStageTableName)
($cpuNumProcessorsColumnName, [UInt16]),
($cpuNameColumnName,[string]),
($cpuCaptionColumnName,[string]),
($cpuFamilyIdColumnName, [UInt16]),
($cpuArchitectureIdColumnName, [UInt16]),
($cpuMaxClockSpeedColumnName, [UInt32]),
($cpuClockSpeedColumnName, [UInt32]),
($cpuL2CacheSizeColumnName, [UInt32]),
($cpuL3CacheSizeColumnName, [UInt32]),
($cpuInstanceProcessorUsageStartTicks, [UInt64]),
($cpuInstanceCollectTimeStartTicks, [Int64]),
($cpuComputerProcessorIdleStartTicks, [UInt64]),
($cpuComputerCollectTimeStartTicks, [UInt64]),
($cpuInstanceProcessorUsageEndTicks, [UInt64]),
($cpuInstanceCollectTimeEndTicks, [Int64]),
($cpuComputerProcessorIdleEndTicks, [UInt64]),
($cpuComputerCollectTimeEndTicks, [UInt64]) |
foreach { ,
$column = new-object Data.DataColumn ($_)
$global:cpuStageDataTable.Columns.Add($column)
}
}
$global:cpuStageDataTable.TableName = $global:cpuStageTableName
}
# If there is one row in the table, it is the data that the query returned
# update the start values to be the old end values
if ($global:cpuStageDataTable.Rows.Count -eq 1)
{
Write-ScriptVerbose "Stage table contains one row. Swapping end to start values."
$dataRow = [System.Data.DataRow] $global:cpuStageDataTable.Rows[0]
# The previous end values become the start values
$dataRow[$cpuInstanceProcessorUsageStartTicks] = $dataRow[$cpuInstanceProcessorUsageEndTicks]
$dataRow[$cpuInstanceCollectTimeStartTicks] = $dataRow[$cpuInstanceCollectTimeEndTicks]
$dataRow[$cpuComputerProcessorIdleStartTicks] = $dataRow[$cpuComputerProcessorIdleEndTicks]
$dataRow[$cpuComputerCollectTimeStartTicks] = $dataRow[$cpuComputerCollectTimeEndTicks]
}
else
{
# There were no rows in the table or too many rows
# Either way, the data needs to be cleared and updated
# with the new information
$rowCount = $global:cpuStageDataTable.Rows.Count
Write-ScriptVerbose "Number of rows in data table is $rowCount"
Write-ScriptVerbose "Clearing stage table and marking start values with 0"
[Void] $global:cpuStageDataTable.Clear()
$dataRow = [System.Data.DataRow] $global:cpuStageDataTable.NewRow()
$global:cpuStageDataTable.Rows.Add($dataRow)
# There are no start values
$dataRow[$cpuInstanceProcessorUsageStartTicks] = 0
$dataRow[$cpuInstanceCollectTimeStartTicks] = 0
$dataRow[$cpuComputerProcessorIdleStartTicks] = 0
$dataRow[$cpuComputerCollectTimeStartTicks] = 0
}
}
process
{
# Powershell 2.0 does not default typed parameters that are $null
# So, the function has to set the defaults for the null parameters
[Int32] $numProcessors = Get-NumericDefaultIfNull $numProcessors
[String] $cpuName = Get-StringDefaultIfNull $cpuName
[String] $cpuCaption = Get-StringDefaultIfNull $cpuCaption
[UInt16] $cpuFamily = Get-NumericDefaultIfNull $cpuFamily
[UInt16] $architecture = Get-NumericDefaultIfNull $architecture
[UInt32] $cpuMaxClockSpeed = Get-NumericDefaultIfNull $cpuMaxClockSpeed
[UInt32] $clockSpeed = Get-NumericDefaultIfNull $clockSpeed
[UInt32] $l2CacheSize = Get-NumericDefaultIfNull $l2CacheSize
[UInt32] $l3CacheSize = Get-NumericDefaultIfNull $l3CacheSize
[UInt64] $instanceProcessorUsage = Get-NumericDefaultIfNull $instanceProcessorUsage
[Int64] $instanceCollectTime = Get-NumericDefaultIfNull $instanceCollectTime
[UInt64] $computerIdleTime = Get-NumericDefaultIfNull $computerIdleTime
[UInt64] $computerCollectTime = Get-NumericDefaultIfNull $computerCollectTime
# instanceCollectTime comes in as an signed int, make sure it is not neg
if($instanceCollectTime -lt 0)
{
$instanceCollectTime = 0
}
# numProcessors comes in as an signed int, make sure it is not neg
if($numProcessors -lt 0)
{
$numProcessors = 0
}
# Add the collected information
Write-ScriptVerbose "Adding collected information to data table"
$dataRow[$cpuNumProcessorsColumnName] = $numProcessors
$dataRow[$cpuNameColumnName] = $cpuName
$dataRow[$cpuCaptionColumnName] = $cpuCaption
$dataRow[$cpuFamilyIdColumnName] = $cpuFamily
$dataRow[$cpuArchitectureIdColumnName] = $architecture
$dataRow[$cpuMaxClockSpeedColumnName] = $cpuMaxClockSpeed
$dataRow[$cpuClockSpeedColumnName] = $clockSpeed
$dataRow[$cpuL2CacheSizeColumnName] = $l2CacheSize
$dataRow[$cpuL3CacheSizeColumnName] = $l3CacheSize
$dataRow[$cpuInstanceProcessorUsageEndTicks] = $instanceProcessorUsage
$dataRow[$cpuInstanceCollectTimeEndTicks] = $instanceCollectTime
$dataRow[$cpuComputerProcessorIdleEndTicks] = $computerIdleTime
$dataRow[$cpuComputerCollectTimeEndTicks] = $computerCollectTime
}
}
function Add-StageVolumeRow
{
param ([String]$deviceId,
[String] $volumeNameRaw,
[UInt64] $capacityBytes,
[UInt64] $freeSpaceBytes)
begin
{
# Initialize the stage table
if($global:volumeStageDataTable -eq $null)
{
Write-ScriptVerbose "Volume data table is null, creating table definition."
$global:volumeStageDataTable = New-Object System.Data.DataTable ($global:volumeStageTableName)
($global:volumeDeviceIdColumnName, [String]),
($global:volumeNameColumnName, [String]),
($global:volumeCapacityColumnName, [UInt64]),
($global:volumeFreeSpaceColumnName, [UInt64])|
foreach { ,
$column = new-object Data.DataColumn ($_)
$global:volumeStageDataTable.Columns.Add($column)
}
}
}
process
{
[String] $deviceId = Get-StringDefaultIfNull $deviceId
[String] $formattedName = Get-FormattedVolumeName $volumeNameRaw
[UInt64] $freeSpaceMB = Get-MegabytesFromBytes $freeSpaceBytes
[UInt64] $capacityMB = Get-MegabytesFromBytes $capacityBytes
if ( ($formattedName -eq "") -or ($deviceId -eq ""))
{
Write-ScriptWarning "DeviceId is empty string, or volume name formatting results in empty string. Skipping this row."
Write-ScriptWarning "Device Id = $deviceId. Volume name raw = $volumeNameRaw."
return # return early
}
Write-ScriptVerbose "Adding collected information to data table"
$dataRow = [System.Data.DataRow] $global:volumeStageDataTable.NewRow()
$dataRow[$global:volumeNameColumnName] = $formattedName
$dataRow[$global:volumeFreeSpaceColumnName] = $freeSpaceMB
$dataRow[$global:volumeCapacityColumnName] = $capacityMB
$dataRow[$global:volumeDeviceIdColumnName] = $deviceId
Write-ScriptVerbose "Adding row to table"
[Void] $global:volumeStageDataTable.Rows.Add($dataRow)
}
}
function Add-StageSmoRow
{
param ([Int32] $type, [String] $objUrn, [String] $propertyName, [object] $value)
begin
{
# Initialize the stage table
if($global:smoStageDataTable -eq $null)
{
Write-ScriptVerbose "Smo data table is null, creating table definition."
$global:smoStageDataTable = New-Object System.Data.DataTable ($global:smoStageTableName)
($global:smoTypeColumnName, [Int32]),
($global:smoUrnColumnName, [String]),
($global:smoPropertyNameColumnName, [String]),
($global:smoPropertyValueColumnName, [Object]) |
foreach { ,
$column = new-object Data.DataColumn ($_)
$global:smoStageDataTable.Columns.Add($column)
}
}
}
process
{
# if the type, propertyName, or Urn is null, something is wrong, throw an exception
ValidateNotNullOrEmpty $type
ValidateNotNUllOrEmpty $propertyName
ValidateNotNUllOrEmpty $objUrn
# value can be null sometimes, which is fine. Just throw the row out.
if ( $value -eq $null )
{
Write-ScriptWarning "The value for property $propertyName is null. This property will not be added."
Write-ScriptWarning "(objUrn = $objUrn)) (type = $type)) (propertyName = $propertyName)) (value = $value))"
return # return early
}
Write-ScriptVerbose "Adding collected information for $propertyName to data table"
$dataRow = [System.Data.DataRow] $global:smoStageDataTable.NewRow()
$dataRow[$global:smoTypeColumnName] = $type
$dataRow[$global:smoUrnColumnName] = $objUrn
$dataRow[$global:smoPropertyNameColumnName] = $propertyName
$dataRow[$global:smoPropertyValueColumnName] = $value
$global:smoStageDataTable.Rows.Add($dataRow)
}
}
###############################################################################
# Collection functions
###############################################################################
function Collect-CpuData
{
&{ # PS Try
# Get the Instance-level Performance Data. An instance is identified
# by its process-id
$processId = Get-ProcessId;
Write-ScriptVerbose "Get WMI percent cpu time for process id = $processId"
# Get the total processor time from the wmi object
# PercentProcessorTime is bad property name, it is actually counting the
# total number of ticks (100NS based)
# the instance has spent on processors.
(Get-WmiObject Win32_PerfRawData_PerfProc_Process -filter "IDProcess = ''$processId''") |
%{ $instanceProcessorUsage = $_.PercentProcessorTime };
Write-ScriptVerbose "Get current time for collection time"
# Find the current number of ticks
$instanceCollectTime = [DateTime]::UtcNow.Ticks
Write-ScriptVerbose "Get WMI machine cpu time and time stamp"
# Get the Machine-level Performance Data
(Get-WmiObject Win32_PerfRawData_PerfOS_Processor -filter "Name = ''_Total''") |
%{ $computerIdleTime = $_.PercentProcessorTime;
$computerCollectTime = $_.TimeStamp_Sys100NS };
Write-ScriptVerbose "Get WMI cpu details"
# Get the processor details
(Get-WmiObject Win32_Processor) |
%{$cpuName = $_.Name;
$cpuCaption = $_.Caption;
$cpuFamily = $_.Family;
$architecture = $_.Architecture;
$cpuMaxClockSpeed = $_.MaxClockSpeed;
$clockSpeed = $_.CurrentClockSpeed;
$l2CacheSize = $_.L2CacheSize;
$l3CacheSize = $_.L3CacheSize };
[Int32] $numProcessors = [System.Environment]::ProcessorCount
Write-ScriptVerbose "Add row to cpu information"
Add-StageCpuRow $numProcessors $cpuName $cpuCaption $cpuFamily $architecture $cpuMaxClockSpeed $clockSpeed $l2CacheSize $l3CacheSize $instanceProcessorUsage $instanceCollectTime $computerIdleTime $computerCollectTime
$global:cpuStageDataTable
}
# PS Catch
trap [Exception]
{
Resolve-Error
Write-ScriptError "Caught exception while collecting cpu properties. A WMI query might have failed."
}
}
function Collect-VolumeData
{
&{ # PS Try
if( Get-IsWmiVolumeQueryAvailable )
{
# A null DriveLetter indicates that the volume is a mount point
# Casting DriveLetter to [Boolean] results in False if it is null
Write-ScriptVerbose "Collecting volume information using Win32_Volume"
(Get-Wmiobject Win32_Volume -filter "DriveType = 3") |
%{ Add-StageVolumeRow $_.DeviceId $_.Name $_.Capacity $_.FreeSpace }
}
else
{
# logical disk only collects disk information, not mount point information
# hence passing in false as is_mount_point parameter
Write-ScriptVerbose "Collecting volume information using Win32_LogicalDisk"
(Get-Wmiobject Win32_LogicalDisk -filter "DriveType = 3") |
%{ Add-StageVolumeRow $_.DeviceId $_.Name $_.Size $_.FreeSpace }
}
$global:volumeStageDataTable
}
# PS Catch
trap [Exception]
{
Resolve-Error
Write-ScriptError "Caught exception while collecting volume properties. A WMI query might have failed."
}
}
function Collect-SmoData
{
&{ # PS try
$sqlConnection = Get-Connection
$serverConnection = New-Object Microsoft.SqlServer.Management.Common.ServerConnection $sqlConnection
$server = New-Object Microsoft.SqlServer.Management.Smo.Server($serverConnection);
# remove configurations from this table
$objectsQuery = "SELECT object_type, sfc_query
FROM [msdb].[dbo].[sysutility_mi_smo_objects_to_collect_internal] AS sfc_queries";
$sfcQueries = Get-SqlDataTable $objectsQuery | %{ $_.Rows }
foreach ($sfcQueryRow in $sfcQueries)
{
[Int32] $object_type = $sfcQueryRow.object_type;
$sfcQueryString = $sfcQueryRow.sfc_query.ToString();
Write-ScriptVerbose "Retrieving list of properties to collect"
$propertiesQuery = "SELECT property_name
FROM [msdb].[dbo].[sysutility_mi_smo_properties_to_collect_internal]
WHERE object_type ="+ $object_type.ToString();
$properties = Get-SqlDataTable $propertiesQuery | %{ $_.Rows } | foreach { $_.property_name };
Write-ScriptVerbose "Collecting smo information for sfc query $sfcQueryString"
$oq = New-Object Microsoft.SqlServer.Management.Sdk.Sfc.SfcObjectQuery($server);
$exp = New-Object Microsoft.SqlServer.Management.Sdk.Sfc.SfcQueryExpression($sfcQueryString);
&{ # PS try
# The following call is not itempotent. The code does not run the same
# in debug mode. If you are running in debug mode, any value display
# invalidates the foreach statement.
$en = $oq.ExecuteIterator($exp, $null, $null);
foreach($obj in $en)
{
$objUrn = $obj.Urn.ToString();
Write-ScriptVerbose "Collecting smo information for urn $objUrn"
# For each property get the value and insert it into the smo stage data table
# the statment $obj.$_ retrieves the propety value from the object
# going through the PS provider. If the property is not found or throws an
# exception from the SMO side, the PS provider wraps the property and returns
# an empty value.
$properties |
%{
if ($_ -eq "ProcessorUsage")
{
# for ProcessorUsage, we are in fact collecting the
# the data by ourselves in our own staging table.
# and we do not want to call SMO as this property
# may not exist on downlevel server.
# so here, we put a dummy value and later during upload
# we replace it with our real value.
# Note that we a similar situation for VolumeFreeSpace
# but the solution is different. For VolumeFreeSpace property
# it is not put in the sysutility_mi_smo_properties_to_collect_internal
# and we collect through other means and then do a join on the UCP
# side, versus for ProcessorUsage, we put the property in the list
# and during MI collection, we replace it with our own value.
# The difference is inconsistent and we should change them to behave
# the same in future releases.
Add-StageSmoRow $object_type $objUrn $_ [object]0
}
else
{
Add-StageSmoRow $object_type $objUrn $_ $obj.$_
}
# if this property is FileName, we append volume/mount point info.
if($_ -eq "FileName")
{
Write-ScriptVerbose "Property is FileName, getting volume information"
[String] $mountPointName = Get-MountPointName $obj.FileName
Add-StageSmoRow $object_type $objUrn "mount_point_name" $mountPointName
[String] $deviceId = Get-DeviceIdFromMountPointName $mountPointName
Add-StageSmoRow $object_type $objUrn "volume_device_id" $deviceId
}
}
$psPath = Convert-UrnToPath $objUrn
("powershell_path", $psPath),
("parent_name", $obj.Parent.Name), # If no Parent exists, Ps will return null
("grandparent_name", $obj.Parent.Parent.Name) | # If no Parent.Parent exists, Ps will return null
%{ ,
$propertyName = $_[0]
[String] $value = $_[1] # Cast to string results in $null values becoming ""
if($value -ne "")
{
Add-StageSmoRow $object_type $objUrn $propertyName $value
}
}
}
} # PS catch exception
trap [Exception]
{
Resolve-Error
Write-ScriptError "Caught exception while collecting smo properties."
}
}
$global:smoStageDataTable
} # PS catch exception
trap [Exception]
{
Resolve-Error
Write-ScriptError "Caught exception while collecting smo properties."
}
}
###############################################################################
# Functions that mange the server tables by clearing and loading collected data
###############################################################################
function Clear-AllStagedData
{
# TRUNCATE TABLE removes all rows from a table without logging the
# individual row deletes.
$cpuClearQuery = "TRUNCATE TABLE $global:cpuStageTableName; "
$volumeClearQuery = "TRUNCATE TABLE $global:volumeStageTableName; "
$smoClearQuery = "TRUNCATE TABLE $global:smoStageTableName; "
Invoke-SubmitSqlCommandNonQuery "$cpuClearQuery $volumeClearQuery $smoClearQuery"
}
function Collect-AllStagedData
{
Collect-CpuData | Out-Null
# Should we collect cpu data again?
# This will happen if the script is
# run when there is no data yet in
# the cpu staging table.
if(Get-ShouldCollectCpu)
{
#Wait for some time to pass
Write-ScriptVerbose "Waiting $sleepTimeoutSeconds seconds to collect cpu data."
Start-Sleep -Seconds $sleepTimeoutSeconds
#Collect the data again
Collect-CpuData | Out-Null
}
Collect-SmoData | Out-Null
Collect-VolumeData | Out-Null
}
function Save-AllStagedData
{
Invoke-BulkCopyCommand $global:cpuStageDataTable
Invoke-BulkCopyCommand $global:volumeStageDataTable
Invoke-BulkCopyCommand $global:smoStageDataTable
}
function Invoke-StageData
{
&{ # Try
Collect-AllStagedData
Invoke-BeginTransaction
Clear-AllStagedData
Save-AllStagedData
Invoke-CommitTransaction
Remove-Connection
}
trap [Exception] # Catch
{
Write-ScriptWarning "Error occurred during execution of script."
Write-ScriptWarning "Transaction will be rolled back."
Resolve-Error
Invoke-RollbackTransaction
Remove-Connection
# With ErrorActionPreference=Stop the following line will stop the script
Write-ScriptError "Error. Transaction was rolled back"
}
}
if(Get-IsAgentStep)
{
Invoke-StageData
}'
END
GO
-------------------------------------------------------------------------------
-- Initialize the collection for the managed instance by creating the
-- sysutility_mi jobs that do data collection and upload to the UCP.
--
-- Specifics:
-- If the job does not exists, create the job with the schedule
-- If a utility job exists
-- keep the job so that schedule and history are retained
-- drop the job steps and then recreate them
-------------------------------------------------------------------------------
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_sysutility_mi_initialize_collection]') AND type in (N'P', N'PC'))
BEGIN
RAISERROR('Dropping [dbo].[sp_sysutility_mi_initialize_collection] procedure', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_initialize_collection];
END
GO
RAISERROR('Creating [dbo].[sp_sysutility_mi_initialize_collection] procedure', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_initialize_collection]
WITH EXECUTE AS OWNER
AS
BEGIN
SET NOCOUNT ON;
DECLARE @null_column sysname = NULL
IF ( 0 = (select [dbo].[fn_sysutility_ucp_get_instance_is_mi]()) )
BEGIN
RAISERROR(37006, -1, -1)
RETURN(1)
END
BEGIN TRY
DECLARE @tran_name NVARCHAR(32) = N'sysutility_mi_initialize_collection' -- transaction names can be no more than 32 characters
BEGIN TRANSACTION @tran_name
-- Common variables
DECLARE @job_category sysname = N'Utility - Managed Instance';
DECLARE @job_category_id INT = (SELECT category_id FROM msdb.dbo.syscategories WHERE name=@job_category AND category_class=1)
DECLARE @server_name sysname = N'(local)';
DECLARE @step_id INT;
DECLARE @step_name sysname;
-- Collect and upload job variables
DECLARE @collect_and_upload_job_name sysname = N'sysutility_mi_collect_and_upload';
DECLARE @collect_and_upload_job_description nvarchar(max) = N'Collect configuration and performance information';
DECLARE @collect_and_upload_schedule_name sysname = N'sysutility_mi_collect_and_upload';
DECLARE @collect_and_upload_schedule_minutes int = 15;
DECLARE @collect_and_upload_job_id uniqueidentifier = (SELECT jobs.job_id
FROM [msdb].[dbo].[sysjobs] jobs
WHERE jobs.name = @collect_and_upload_job_name
AND jobs.category_id = @job_category_id);
-- start the job one minute past midnight + some random set of minutes between the schedule interval
-- for agent jobs, a schedule's time is encoded in an integer. The minutes portion
-- are stored in the the 100s and 1000s digits.
DECLARE @collect_and_upload_schedule_start_time int = CAST((1 + RAND() * (@collect_and_upload_schedule_minutes + 1)) AS INT) * 100;
-- end the job one minute before the start time
DECLARE @collect_and_upload_schedule_end_time int = @collect_and_upload_schedule_start_time - 100;
-- Dac performance collection job variables
DECLARE @dac_perf_job_name sysname = N'sysutility_mi_collect_performance';
DECLARE @dac_perf_job_description nvarchar(max) = N'Collect performance information';
DECLARE @dac_perf_schedule_name sysname = N'sysutility_mi_collect_performance';
DECLARE @dac_perf_schedule_seconds int = 15;
DECLARE @dac_perf_job_id uniqueidentifier = (SELECT jobs.job_id
FROM [msdb].[dbo].[sysjobs] jobs
WHERE jobs.name = @dac_perf_job_name
AND jobs.category_id = @job_category_id);
-------------------------------------------------------------------------
-- Create the category for the jobs
-------------------------------------------------------------------------
IF (@job_category_id IS NULL)
BEGIN
RAISERROR('Creating utility job category ... %s', 0, 1, @job_category) WITH NOWAIT;
EXEC msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=@job_category
END
-------------------------------------------------------------------------
-- Prepare the jobs
-------------------------------------------------------------------------
IF (@collect_and_upload_job_id IS NULL)
BEGIN
RAISERROR('Creating utility job ... %s', 0, 1, @collect_and_upload_job_name) WITH NOWAIT;
-- The job doesn't exist yet, create the job
EXEC msdb.dbo.sp_add_job
@job_name=@collect_and_upload_job_name,
@enabled=0, -- create the job disabled
@notify_level_eventlog=0,
@notify_level_email=0,
@notify_level_netsend=0,
@notify_level_page=0,
@delete_level=0,
@description=@collect_and_upload_job_description,
@category_name=@job_category,
@job_id = @collect_and_upload_job_id OUTPUT
RAISERROR('Adding job to jobserver ... %s' , 0, 1, @collect_and_upload_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_add_jobserver @job_id = @collect_and_upload_job_id, @server_name = @server_name
END
ELSE
BEGIN
RAISERROR('Disabling utility job ... %s', 0, 1, @collect_and_upload_job_name) WITH NOWAIT;
-- Disable the job for now. Disable is itempotent
EXEC msdb.dbo.sp_update_job @job_id=@collect_and_upload_job_id, @enabled=0
RAISERROR('Clearing job steps for utility job ... %s', 0, 1, @collect_and_upload_job_name) WITH NOWAIT;
-- The job exists, delete all of the job steps prior to recreating them
-- Passing step_id = 0 to sp_delete_jobstep deletes all job steps for the job
EXEC msdb.dbo.sp_delete_jobstep @job_id=@collect_and_upload_job_id, @step_id = 0
END
IF (@dac_perf_job_id IS NULL)
BEGIN
RAISERROR('Creating utility job ... %s', 0, 1, @dac_perf_job_name) WITH NOWAIT;
-- The job doesn't exist yet, create the job
EXEC msdb.dbo.sp_add_job
@job_name=@dac_perf_job_name,
@enabled=0, -- create the job disabled
@notify_level_eventlog=0,
@notify_level_email=0,
@notify_level_netsend=0,
@notify_level_page=0,
@delete_level=0,
@description=@dac_perf_job_description,
@category_name=@job_category,
@job_id = @dac_perf_job_id OUTPUT
RAISERROR('Adding job to jobserver ... %s' , 0, 1, @dac_perf_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_add_jobserver @job_id = @dac_perf_job_id, @server_name = @server_name
END
ELSE
BEGIN
RAISERROR('Disabling utility job ... %s', 0, 1, @dac_perf_job_name) WITH NOWAIT;
-- Disable the job for now. Disable is itempotent
EXEC msdb.dbo.sp_update_job @job_id=@dac_perf_job_id, @enabled=0
RAISERROR('Clearing job steps for utility job ... %s', 0, 1, @dac_perf_job_name) WITH NOWAIT;
-- The job exists, delete all of the job steps prior to recreating them
-- Passing step_id = 0 to sp_delete_jobstep deletes all job steps for the job
EXEC msdb.dbo.sp_delete_jobstep @job_id=@dac_perf_job_id, @step_id = 0
END
-------------------------------------------------------------------------
-- Add the schedules for the jobs
-------------------------------------------------------------------------
IF NOT EXISTS (SELECT name FROM msdb.dbo.sysschedules_localserver_view WHERE name = @collect_and_upload_schedule_name)
BEGIN
RAISERROR('Creating schedule ... %s', 0, 1, @collect_and_upload_schedule_name) WITH NOWAIT;
EXEC dbo.sp_add_schedule
@schedule_name = @collect_and_upload_schedule_name, -- Schedule name
@enabled=1, -- Enabled
@freq_type = 4, -- Daily
@freq_interval = 1, -- Recurs every 1 day
@freq_subday_type = 0x4, -- Frequency type is "minutes"
@freq_subday_interval = @collect_and_upload_schedule_minutes, -- Occurs every x minutes
@active_start_time = @collect_and_upload_schedule_start_time, -- Time to start the job
@active_end_time = @collect_and_upload_schedule_end_time -- Time to end the job
END
-- attach the schedule. attach_schedule is itempotent if the job already has the schedule attached
RAISERROR('Attaching schedule %s to job %s ...' , 0, 1, @collect_and_upload_schedule_name, @collect_and_upload_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_attach_schedule @job_id=@collect_and_upload_job_id,@schedule_name=@collect_and_upload_schedule_name
IF NOT EXISTS (SELECT name FROM msdb.dbo.sysschedules_localserver_view WHERE name = @dac_perf_schedule_name)
BEGIN
RAISERROR('Creating schedule ... %s', 0, 1, @dac_perf_schedule_name) WITH NOWAIT;
EXEC dbo.sp_add_schedule
@schedule_name = @dac_perf_schedule_name, -- Schedule name
@enabled=1, -- Enabled
@freq_type = 4, -- Daily
@freq_interval = 1, -- Recurs every 1 day
@freq_subday_type = 0x2, -- Frequency type is "seconds"
@freq_subday_interval = @dac_perf_schedule_seconds -- Occurs every x seconds
END
-- attach the schedule. attach_schedule is itempotent if the job already has the schedule attached
RAISERROR('Attaching schedule %s to job %s ...' , 0, 1, @dac_perf_schedule_name, @dac_perf_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_attach_schedule @job_id=@dac_perf_job_id,@schedule_name=@dac_perf_schedule_name
-------------------------------------------------------------------------
-- Add the steps
-------------------------------------------------------------------------
-------------------------------------------------------------------------
-- Steps for dac performance job
-------------------------------------------------------------------------
SET @step_id = 1;
SET @step_name = N'Collect DAC execution statistics';
RAISERROR('Adding step %i name %s to job %s', 0, 1, @step_id, @step_name, @dac_perf_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_add_jobstep
@job_id=@dac_perf_job_id,
@step_name=@step_name,
@step_id=1,
@cmdexec_success_code=0,
@on_success_action=1,
@on_fail_action=3,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0, @subsystem=N'TSQL',
@command=N'EXEC [msdb].[dbo].[sp_sysutility_mi_collect_dac_execution_statistics_internal]',
@database_name=N'msdb',
@flags=0
-------------------------------------------------------------------------
-- Steps for collect and upload job
-------------------------------------------------------------------------
-- Job step to record the current time on the managed instance. This value will be included in the output of all of
-- the queries executed by the Utility collection set. It will be used on the UCP to tie together all of the data from
-- a single execution of the data collection job.
--
-- We create a table in tempdb to hold last batch start time and other transient data that does not
-- need to survive a service cycle. Nothing uses this table except subsequent steps in this job;
-- it is safe to drop and recreate it here so that we do not need to worry about build-to-build
-- schema changes.
SET @step_id = 1;
SET @step_name = N'Record batch start time';
RAISERROR('Adding step %i name %s to job %s', 0, 1, @step_id, @step_name, @collect_and_upload_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_add_jobstep @job_id=@collect_and_upload_job_id, @step_name=@step_name,
@step_id=@step_id,
@cmdexec_success_code=0,
@on_success_action=3, -- Go to next step
@on_fail_action=2, -- Quit the job reporting failure. If something goes wrong here, something is messed up
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'TSQL',
@command='
USE tempdb
IF OBJECT_ID (''[tempdb].[dbo].[sysutility_batch_time_internal]'') IS NOT NULL
BEGIN
DROP TABLE [tempdb].[dbo].[sysutility_batch_time_internal];
END;
CREATE TABLE [tempdb].[dbo].[sysutility_batch_time_internal] (
latest_batch_time datetimeoffset(7) PRIMARY KEY NOT NULL
);
-- The DC job needs to access the timestamp in this table, and it may not run under a login that
-- is mapped to a user in tempdb, so grant SELECT permissions to public. The table contains no
-- sensitive data (only a single datetimeoffset value), so granting read permission to public
-- does create a security problem.
GRANT SELECT ON [tempdb].[dbo].[sysutility_batch_time_internal] TO PUBLIC;
-- Save the start time for the current execution of the managed instance data collection job
INSERT INTO [tempdb].[dbo].[sysutility_batch_time_internal] (latest_batch_time) VALUES (SYSDATETIMEOFFSET());',
@database_name=N'tempdb',
@flags=0
DECLARE @psScript NVARCHAR(MAX) = (SELECT [dbo].[fn_sysutility_mi_get_collect_script]());
SET @step_id = 2;
SET @step_name = N'Stage Data Collected from PowerShell Script';
RAISERROR('Adding step %i name %s to job %s', 0, 1, @step_id, @step_name, @collect_and_upload_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_add_jobstep @job_id=@collect_and_upload_job_id, @step_name=@step_name,
@step_id=@step_id,
@cmdexec_success_code=0,
@on_success_action=3, -- Go to next step
@on_fail_action=2, -- Quit the job reporting failure
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'PowerShell',
@command=@psScript,
@database_name=N'master',
@flags=0
SET @step_id = 3;
SET @step_name = N'Upload to Utility Control Point';
RAISERROR('Adding step %i name %s to job %s', 0, 1, @step_id, @step_name, @collect_and_upload_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_add_jobstep @job_id=@collect_and_upload_job_id, @step_name=@step_name,
@step_id=@step_id,
@cmdexec_success_code=0,
@on_success_action=1, -- Quit the job reporting success
@on_fail_action=2, -- Quit the job reporting failure
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'TSQL',
@command=N'EXEC [msdb].[dbo].[sp_sysutility_mi_upload]',
@database_name=N'msdb',
@flags=0
-- Capture an initial snapshot of DAC statistics. This is not strictly necessary, but it will ensure that we
-- can calculate interval statistics immediately on the first execution of the every-15-second scheduled job.
RAISERROR('Collecting dac execution statistics for the first time ...', 0, 1, @collect_and_upload_job_name) WITH NOWAIT;
EXEC [msdb].[dbo].[sp_sysutility_mi_collect_dac_execution_statistics_internal]
-- Enable the jobs
RAISERROR('Enabling job ... %s', 0, 1, @collect_and_upload_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_update_job @job_id=@collect_and_upload_job_id, @enabled=1
RAISERROR('Enabling job ... %s', 0, 1, @dac_perf_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_update_job @job_id=@dac_perf_job_id, @enabled=1
-- Start the jobs
RAISERROR('Starting job ... %s', 0, 1, @collect_and_upload_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_start_job @job_id=@collect_and_upload_job_id
RAISERROR('Starting job ... %s', 0, 1, @dac_perf_job_name) WITH NOWAIT;
EXEC msdb.dbo.sp_start_job @job_id=@dac_perf_job_id
COMMIT TRANSACTION @tran_name
END TRY
BEGIN CATCH
-- Roll back our transaction if it's still open
IF (@@TRANCOUNT > 0)
BEGIN
ROLLBACK TRANSACTION;
END;
-- Rethrow the error. Unfortunately, we can't retrow the exact same error number b/c RAISERROR
-- does not allow you to use error numbers below 13000. We rethrow error 14684:
-- Caught error#: %d, Level: %d, State: %d, in Procedure: %s, Line: %d, with Message: %s
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, -1, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
END CATCH;
END
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_sysutility_mi_disable_collection]') AND type in (N'P', N'PC'))
BEGIN
RAISERROR('Dropping [dbo].[sp_sysutility_mi_disable_collection] procedure', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_disable_collection];
END
GO
RAISERROR('Creating [dbo].[sp_sysutility_mi_disable_collection] procedure', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_disable_collection]
WITH EXECUTE AS OWNER
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
DECLARE @tran_name NVARCHAR(32) = N'sysutility_mi_disable_colle' -- transaction names can be no more than 32 characters
BEGIN TRANSACTION @tran_name
DECLARE @job_category sysname = N'Utility - Managed Instance';
DECLARE @job_category_id INT = (SELECT category_id FROM msdb.dbo.syscategories WHERE name=@job_category AND category_class=1)
DECLARE @collect_and_upload_job_name sysname = N'sysutility_mi_collect_and_upload';
DECLARE @collect_and_upload_job_id uniqueidentifier = (SELECT jobs.job_id
FROM [msdb].[dbo].[sysjobs] jobs
WHERE jobs.name = @collect_and_upload_job_name
AND jobs.category_id = @job_category_id);
-- Dac performance collection job varaibles
DECLARE @dac_perf_job_name sysname = N'sysutility_mi_collect_performance';
DECLARE @dac_perf_job_id uniqueidentifier = (SELECT jobs.job_id
FROM [msdb].[dbo].[sysjobs] jobs
WHERE jobs.name = @dac_perf_job_name
AND jobs.category_id = @job_category_id);
IF(@collect_and_upload_job_id IS NOT NULL)
BEGIN
EXEC msdb.dbo.sp_update_job @job_id=@collect_and_upload_job_id, @enabled=0;
END
IF(@dac_perf_job_id IS NOT NULL)
BEGIN
EXEC msdb.dbo.sp_update_job @job_id=@dac_perf_job_id, @enabled=0;
END
COMMIT TRANSACTION @tran_name
END TRY
BEGIN CATCH
-- Roll back our transaction if it's still open
IF (@@TRANCOUNT > 0)
BEGIN
ROLLBACK TRANSACTION;
END;
-- Rethrow the error. Unfortunately, we can't retrow the exact same error number b/c RAISERROR
-- does not allow you to use error numbers below 13000. We rethrow error 14684:
-- Caught error#: %d, Level: %d, State: %d, in Procedure: %s, Line: %d, with Message: %s
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
DECLARE @ErrorNumber INT;
DECLARE @ErrorLine INT;
DECLARE @ErrorProcedure NVARCHAR(200);
SELECT @ErrorLine = ERROR_LINE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
RAISERROR (14684, -1, -1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
END CATCH;
END
GO
/**********************************************************************/
/* */
/* Validate the instance can be used as a UCP. */
/* */
/* Note that this function calls xp_qv, which requires that the */
/* 'AgentXPs' sp_configure value be enabled. During upgrade this */
/* setting will need to be manually enabled, since upgrade scripts */
/* are executed while Agent is stopped. */
/**********************************************************************/
/*
Function [fn_sysutility_ucp_get_edition_is_ucp_capable_internal]
Returns 1 if this SQL instance's edition allows it to become a UCP.
*/
IF OBJECT_ID ('dbo.fn_sysutility_ucp_get_edition_is_ucp_capable_internal') IS NOT NULL
BEGIN
RAISERROR ('Dropping function [dbo].[fn_sysutility_ucp_get_edition_is_ucp_capable_internal]', 0, 1) WITH NOWAIT;
DROP FUNCTION dbo.fn_sysutility_ucp_get_edition_is_ucp_capable_internal;
END;
GO
RAISERROR ('Creating function [dbo].[fn_sysutility_ucp_get_edition_is_ucp_capable_internal]', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION dbo.fn_sysutility_ucp_get_edition_is_ucp_capable_internal ()
RETURNS bit
AS
BEGIN
DECLARE @is_instance_ucp_capable bit = 1;
-- The integer value below corresponds to a SQLBOOT property that identifies whether
-- the SKU supports the UCP feature.
DECLARE @sqlbootvalue int;
EXEC @sqlbootvalue = master.dbo.xp_qv '1675385081', @@SERVICENAME;
IF (@sqlbootvalue != 2)
BEGIN
SET @is_instance_ucp_capable = 0;
END;
RETURN @is_instance_ucp_capable;
END
GO
/*
Procedure [sp_sysutility_ucp_validate_prerequisites]
The procedure validates that the local instance can be used as a UCP
*/
IF OBJECT_ID ('dbo.sp_sysutility_ucp_validate_prerequisites') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_ucp_validate_prerequisites]', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_validate_prerequisites
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_ucp_validate_prerequisites]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_validate_prerequisites]
WITH EXECUTE AS OWNER
AS
BEGIN
IF (dbo.fn_sysutility_ucp_get_edition_is_ucp_capable_internal() = 1)
BEGIN
RAISERROR ('Instance is able to be used as a Utility Control Point.', 0, 1) WITH NOWAIT;
END
ELSE BEGIN
DECLARE @edition nvarchar(128);
SELECT @edition = CONVERT(nvarchar(128), SERVERPROPERTY('Edition'));
RAISERROR(37004, -1, -1, @edition);
RETURN(1);
END;
END
GO
/**********************************************************************/
/* */
/* Run the process to turn the local instance into a UCP */
/* */
/**********************************************************************/
/*
Procedure [sp_sysutility_ucp_create]
The procedure runs the process that turns the local instance into a UCP
*/
IF OBJECT_ID ('dbo.sp_sysutility_ucp_create') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_ucp_create]', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_create
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_ucp_create]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_create]
WITH EXECUTE AS OWNER
AS
BEGIN
/* Validate that the UCP can be created on the local instance. */
EXEC [dbo].[sp_sysutility_ucp_validate_prerequisites]
END
GO
/**********************************************************************/
/* */
/* Validate the instance can be managed. */
/* */
/**********************************************************************/
/*
Procedure [sp_sysutility_mi_validate_enrollment_preconditions]
The procedure validates that the local instance can be made managed
*/
IF OBJECT_ID ('dbo.sp_sysutility_mi_validate_enrollment_preconditions') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_mi_validate_enrollment_preconditions]', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_mi_validate_enrollment_preconditions
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_mi_validate_enrollment_preconditions]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_validate_enrollment_preconditions]
WITH EXECUTE AS OWNER
AS
BEGIN
/* Get the Edition value */
DECLARE @edition NVARCHAR(64)
SELECT @edition = Convert(NVARCHAR, SERVERPROPERTY('edition'))
/* Check SQLBOOT to ensure this instance edition can be used as a UCP. */
DECLARE @sqlbootvalue int
EXEC @sqlbootvalue = master.dbo.xp_qv '3090395820', @@SERVICENAME
IF (@sqlbootvalue = 2)
RAISERROR ('Instance can be managed by a Utility Control Point.', 0, 1) WITH NOWAIT;
ELSE
RAISERROR(37005, -1, -1, @edition)
RETURN(1)
END
GO
/**********************************************************************/
/* */
/* Run the process to make the local instance managed by a UCP. */
/* */
/**********************************************************************/
/*
Procedure [sp_sysutility_mi_enroll]
The procedure runs the process that makes the local instance managed by a UCP.
*/
IF OBJECT_ID ('dbo.sp_sysutility_mi_enroll') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_mi_enroll]', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_mi_enroll
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_mi_enroll]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_enroll]
WITH EXECUTE AS OWNER
AS
BEGIN
/* Validate that the local instance can be managed by a UCP. */
EXEC [dbo].[sp_sysutility_mi_validate_enrollment_preconditions]
END
GO
/**********************************************************************/
/* Object types handled by the UCP */
/* */
/* We treat DACs and Databases as synonymous for this purpose */
/**********************************************************************/
IF(OBJECT_ID(N'[dbo].[sysutility_ucp_supported_object_types_internal]', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table [dbo].[sysutility_ucp_supported_object_types_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE [sysutility_ucp_supported_object_types_internal] (
[object_type] INT,
[object_name] NVARCHAR(32),
CONSTRAINT PK_sysutility_ucp_supported_object_types_internal
PRIMARY KEY([object_type])
)
INSERT INTO [sysutility_ucp_supported_object_types_internal] VALUES (0, 'Utility')
INSERT INTO [sysutility_ucp_supported_object_types_internal] VALUES (1, 'Computer')
INSERT INTO [sysutility_ucp_supported_object_types_internal] VALUES (2, 'Volume')
INSERT INTO [sysutility_ucp_supported_object_types_internal] VALUES (3, 'Instance')
INSERT INTO [sysutility_ucp_supported_object_types_internal] VALUES (4, 'Database')
INSERT INTO [sysutility_ucp_supported_object_types_internal] VALUES (5, 'FileGroup')
INSERT INTO [sysutility_ucp_supported_object_types_internal] VALUES (6, 'DataFile')
INSERT INTO [sysutility_ucp_supported_object_types_internal] VALUES (7, 'LogFile')
END
GO
/**********************************************************************/
/* Create the managed instance table */
/* */
/* */
/**********************************************************************/
IF(OBJECT_ID(N'[dbo].[sysutility_ucp_managed_instances_internal]', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table [dbo].[sysutility_ucp_managed_instances_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE [sysutility_ucp_managed_instances_internal] (
instance_id int IDENTITY(1,1),
instance_name sysname,
virtual_server_name sysname,
date_created datetimeoffset(7) NOT NULL default SYSDATETIMEOFFSET(),
created_by sysname NOT NULL default SUSER_SNAME(),
agent_proxy_account sysname NOT NULL,
cache_directory nvarchar(520),
management_state int NOT NULL default (0),
CONSTRAINT [UQ_sysutility_ucp_mi_id] UNIQUE (instance_id ASC),
CONSTRAINT [PK_sysutility_ucp_mi_name] PRIMARY KEY CLUSTERED (instance_name)
);
END
GO
/**********************************************************************/
/* create the managed instance view */
/* */
/**********************************************************************/
IF(OBJECT_ID(N'[dbo].[sysutility_ucp_managed_instances]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_managed_instances]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_managed_instances]
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_managed_instances]...', 0, 1) WITH NOWAIT;
GO
CREATE VIEW [dbo].[sysutility_ucp_managed_instances]
AS
SELECT
instance_id,
instance_name,
virtual_server_name,
date_created,
created_by,
agent_proxy_account,
cache_directory,
management_state
FROM [dbo].[sysutility_ucp_managed_instances_internal]
GO
/**********************************************************************/
/* Add managed instance to the store. */
/* */
/* */
/**********************************************************************/
/*
Procedure [sp_sysutility_ucp_add_mi]
This proc creates a new ManagedInstance in dbo.sysutility_ucp_managed_instances_internal table
Parameters:
@instance_name -
@agent_proxy_account -
@cache_directory -
@management_state -
@instance_id
*/
IF OBJECT_ID ('dbo.sp_sysutility_ucp_add_mi') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_ucp_add_mi]', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_add_mi
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_ucp_add_mi]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_add_mi]
@instance_name sysname,
@virtual_server_name sysname,
@agent_proxy_account sysname,
@cache_directory nvarchar(520),
@management_state int,
@instance_id int = NULL OUTPUT
WITH EXECUTE AS OWNER
AS
BEGIN
SET NOCOUNT ON
DECLARE @retval INT
DECLARE @null_column nvarchar(600)
SET @null_column = NULL
IF (@instance_name IS NULL OR @instance_name = N'')
SET @null_column = '@instance_name'
ELSE IF (@virtual_server_name IS NULL OR @virtual_server_name = N'')
SET @null_column = '@virtual_server_name'
ELSE IF (@management_state IS NULL)
SET @null_column = '@management_state'
ELSE IF (@agent_proxy_account IS NULL OR @agent_proxy_account = N'')
SET @null_column = '@agent_proxy_account'
-- @cache_directory can be null or empty
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_ucp_add_mi')
RETURN(1)
END
IF EXISTS (SELECT * FROM dbo.sysutility_ucp_managed_instances_internal WHERE (instance_name = @instance_name))
BEGIN
RAISERROR(34010, -1, -1, 'Managed_Instance', @instance_name)
RETURN(1)
END
INSERT INTO [dbo].[sysutility_ucp_managed_instances_internal]
(instance_name, virtual_server_name, agent_proxy_account, cache_directory, management_state)
VALUES
(@instance_name, @virtual_server_name, @agent_proxy_account, @cache_directory, @management_state)
SELECT @retval = @@error
SET @instance_id = SCOPE_IDENTITY()
RETURN(@retval)
END
GO
/**************************************************************************/
/* create the Utility Processing State table */
/* This table is a single-row table containing internal state information */
/* for UCP processing. The two columns that it stores currently are */
/* latest_processing_time: the time at which data from the "live" tables */
/* is copied over to the "cache" tables". */
/* latest_health_state_id: a sequence number that all the health_state */
/* tables use to represent the "latest" health */
/* state calculation. */
/* */
/**************************************************************************/
IF(OBJECT_ID(N'[dbo].[sysutility_ucp_processing_state_internal]', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table [dbo].[sysutility_ucp_processing_state_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_processing_state_internal] (
latest_processing_time DATETIMEOFFSET(7),
latest_health_state_id INT,
next_health_state_id INT,
[id] AS 1,
CONSTRAINT CK_sysutility_ucp_processing_state_internal
CHECK (latest_health_state_id <= next_health_state_id),
CONSTRAINT PK_sysutility_ucp_processing_state_internal
PRIMARY KEY([id]) -- enforce single row in this table
);
INSERT INTO [dbo].[sysutility_ucp_processing_state_internal](latest_processing_time, latest_health_state_id, next_health_state_id)
VALUES (SYSDATETIMEOFFSET(), 0, 1);
END;
GO
/**********************************************************************/
/* create the Utility registration creation stored procedure */
/* */
/**********************************************************************/
IF OBJECT_ID ('dbo.sp_sysutility_ucp_initialize') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_ucp_initialize]', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_ucp_initialize]
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_ucp_initialize]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_initialize]
@utility_name sysname,
@mdw_database_name sysname,
@description nvarchar(1024) = N''
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @retval INT
DECLARE @null_column sysname
SET @null_column = NULL
IF (@utility_name IS NULL OR @utility_name = N'')
SET @null_column = '@utility_name'
ELSE IF (@mdw_database_name IS NULL OR @mdw_database_name = N'')
SET @null_column = '@mdw_database_name'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_ucp_initialize')
RETURN(1)
END
-- Make sure that the Utility wasn't already created
DECLARE @utilityName sysname
set @utilityName = (SELECT CAST (current_value as sysname) FROM msdb.dbo.sysutility_ucp_configuration_internal where name = 'UtilityName')
IF (@utilityName IS NOT NULL AND @utilityName != N'')
BEGIN
RAISERROR(37003, -1, -1)
RETURN(1)
END
IF NOT EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE name = @mdw_database_name)
BEGIN
RAISERROR(37002, -1, -1, @mdw_database_name)
RETURN(1)
END
UPDATE dbo.sysutility_ucp_configuration_internal
SET current_value = @utility_name WHERE name = N'UtilityName'
UPDATE dbo.sysutility_ucp_configuration_internal
SET current_value = @mdw_database_name WHERE name = N'MdwDatabaseName'
UPDATE dbo.sysutility_ucp_configuration_internal
SET current_value = SYSDATETIMEOFFSET() WHERE name = N'UtilityDateCreated'
UPDATE dbo.sysutility_ucp_configuration_internal
SET current_value = SUSER_SNAME() WHERE name = N'UtilityCreatedBy'
IF (@description IS NOT NULL AND @description != N'')
BEGIN
UPDATE dbo.sysutility_ucp_configuration_internal
SET current_value = @description WHERE name = N'UtilityDescription'
END
DECLARE @utility_version SYSNAME
set @utility_version = (SELECT CAST(current_value AS SYSNAME) FROM
[msdb].[dbo].[sysutility_ucp_configuration_internal]
WHERE name = N'UtilityVersion')
---- Add the UtilityVersion, UcpName and the UcpFriendlyName registry key values.
EXEC master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'UtilityVersion',
N'REG_SZ',
@utility_version
EXEC master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'UcpName',
N'REG_SZ',
@@SERVERNAME
EXEC master.dbo.xp_instance_regwrite N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'UcpFriendlyName',
N'REG_SZ',
@utility_name
END
GO
/**********************************************************************/
/* Create procedure sp_sysutility_ucp_update_utility_configuration */
/**********************************************************************/
IF OBJECT_ID ('[dbo].sp_sysutility_ucp_update_utility_configuration') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_ucp_update_utility_configuration]', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].sp_sysutility_ucp_update_utility_configuration
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_ucp_update_utility_configuration]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_update_utility_configuration]
@name SYSNAME,
@value SQL_VARIANT
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @retval INT
DECLARE @null_column SYSNAME
SET @null_column = NULL
IF (@name IS NULL OR @name = N'')
SET @null_column = '@name'
ELSE IF (@value IS NULL)
SET @null_column = '@value'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_ucp_update_utility_configuration')
RETURN(1)
END
IF NOT EXISTS (SELECT 1 FROM dbo.sysutility_ucp_configuration_internal WHERE name = @name)
BEGIN
RAISERROR(14027, -1, -1, @name)
RETURN(1)
END
UPDATE dbo.sysutility_ucp_configuration_internal SET current_value = @value WHERE name = @name
SELECT @retval = @@error
RETURN(@retval)
END
GO
/**********************************************************************/
/* Create procedure fn_sysutility_ucp_accepts_upload_schema_version */
/* This procedure is used to identify whether an MI's upload schema */
/* is compatible with this UCP. If a breaking change is introduced */
/* that would cause an incompatibility between an MI and UCP. This */
/* function should be updated accordingly along with the */
/* mi_configuration view */
/* */
/* REASON CODES: */
/* -1 : Schema version is too low, upgrade MI */
/* 0 : Schema is accepted */
/* 1 : Schema version is too high, upgrade UCP */
/**********************************************************************/
IF OBJECT_ID ('[dbo].fn_sysutility_ucp_accepts_upload_schema_version') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[fn_sysutility_ucp_accepts_upload_schema_version]', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].fn_sysutility_ucp_accepts_upload_schema_version
END;
GO
RAISERROR ('Creating procedure [dbo].[fn_sysutility_ucp_accepts_upload_schema_version]', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_ucp_accepts_upload_schema_version]
(
@upload_schema_version INT
)
RETURNS INT
AS
BEGIN
DECLARE @accepted_min_version INT = 100;
DECLARE @accepted_max_version INT = 100;
-- Assume that the version is compatable
DECLARE @retvalue INT = 0;
IF(@upload_schema_version < @accepted_min_version)
SET @retvalue = -1
ELSE IF(@upload_schema_version > @accepted_max_version)
SET @retvalue = 1
RETURN @retvalue
END
GO
/**********************************************************************/
/* Create the resource health policies table */
/**********************************************************************/
IF(OBJECT_ID(N'[dbo].[sysutility_ucp_health_policies_internal]', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table [dbo].[sysutility_ucp_health_policies_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_health_policies_internal] (
health_policy_id INT IDENTITY(1,1),
policy_name SYSNAME NOT NULL,
rollup_object_urn NVARCHAR(4000) NOT NULL,
rollup_object_type INT NOT NULL,
target_type INT NOT NULL,
resource_type INT NOT NULL,
utilization_type INT NOT NULL,
utilization_threshold FLOAT NOT NULL,
is_global_policy BIT DEFAULT 0
CONSTRAINT [PK_sysutility_ucp_policies_internal_id] PRIMARY KEY CLUSTERED (health_policy_id ASC),
);
CREATE NONCLUSTERED INDEX [NCI_sysutility_resource_health_policies_urn_types] ON
[dbo].[sysutility_ucp_health_policies_internal]([rollup_object_type],
[target_type],
[resource_type],
[utilization_type],
[policy_name]) INCLUDE([rollup_object_urn]);
END
GO
/**********************************************************************/
/* Create the resource health policies view */
/**********************************************************************/
IF object_id(N'dbo.sysutility_ucp_policies', 'V') IS NOT NULL
DROP VIEW dbo.sysutility_ucp_policies
GO
CREATE VIEW dbo.sysutility_ucp_policies
AS
SELECT
rhp.health_policy_id AS health_policy_id,
p.policy_id AS policy_id,
rhp.policy_name AS policy_name,
rhp.rollup_object_type AS rollup_object_type,
rhp.rollup_object_urn AS rollup_object_urn,
rhp.target_type AS target_type,
rhp.resource_type AS resource_type,
rhp.utilization_type AS utilization_type,
rhp.utilization_threshold AS utilization_threshold,
rhp.is_global_policy AS is_global_policy
FROM [msdb].[dbo].[sysutility_ucp_health_policies_internal] rhp
INNER JOIN msdb.dbo.syspolicy_policies p ON p.name = rhp.policy_name
GO
/**********************************************************************/
/* Create procedure sp_sysutility_ucp_add_policy */
/* Creates the resource health policy record for specified as input details */
/**********************************************************************/
IF OBJECT_ID ('dbo.sp_sysutility_ucp_add_policy') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_ucp_add_policy]', 0, 1) WITH NOWAIT;
DROP PROCEDURE sp_sysutility_ucp_add_policy
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_ucp_add_policy]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_add_policy]
@policy_name SYSNAME,
@rollup_object_type INT,
@rollup_object_urn NVARCHAR(4000),
@target_type INT,
@resource_type INT,
@utilization_type INT,
@utilization_threshold FLOAT,
@resource_health_policy_id INT = NULL OUTPUT
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @retval INT
DECLARE @null_column SYSNAME
SET @null_column = NULL
IF (@policy_name IS NULL OR @policy_name = N'')
SET @null_column = '@policy_name'
ELSE IF (@rollup_object_type IS NULL OR @rollup_object_type < 1 OR @rollup_object_type > 3)
SET @null_column = '@rollup_object_type'
ELSE IF (@rollup_object_urn IS NULL OR @rollup_object_urn = N'')
SET @null_column = '@rollup_object_urn'
ELSE IF (@target_type IS NULL OR @target_type < 1 OR @target_type > 6)
SET @null_column = '@target_type'
ELSE IF (@resource_type IS NULL OR @resource_type < 1 OR @resource_type > 5)
SET @null_column = '@resource_type'
ELSE IF (@utilization_type IS NULL OR @utilization_type < 1 OR @utilization_type > 2)
SET @null_column = '@utilization_type'
ELSE IF (@utilization_threshold IS NULL OR @utilization_threshold < 0 OR @utilization_threshold > 100)
SET @null_column = '@utilization_threshold'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_ucp_add_policy')
RETURN(1)
END
IF NOT EXISTS (SELECT * FROM dbo.syspolicy_policies WHERE name = @policy_name)
BEGIN
RAISERROR(14027, -1, -1, @policy_name)
RETURN(1)
END
INSERT INTO dbo.sysutility_ucp_health_policies_internal(policy_name, rollup_object_type, rollup_object_urn, target_type, resource_type, utilization_type, utilization_threshold)
VALUES(@policy_name, @rollup_object_type, @rollup_object_urn, @target_type, @resource_type, @utilization_type, @utilization_threshold)
SELECT @retval = @@error
SET @resource_health_policy_id = SCOPE_IDENTITY()
RETURN(@retval)
END
GO
/**********************************************************************/
/* Create procedure sp_sysutility_ucp_delete_policy */
/* Deletes the resource health policy record for the id specified as input */
/**********************************************************************/
IF OBJECT_ID ('dbo.sp_sysutility_ucp_delete_policy') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_ucp_delete_policy]', 0, 1) WITH NOWAIT;
DROP PROCEDURE sp_sysutility_ucp_delete_policy
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_ucp_delete_policy]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_delete_policy]
@resource_health_policy_id INT
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @retval INT
DECLARE @null_column SYSNAME
SET @null_column = NULL
IF (@resource_health_policy_id IS NULL OR @resource_health_policy_id = 0)
SET @null_column = '@resource_health_policy_id'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_ucp_delete_policy')
RETURN(1)
END
IF NOT EXISTS (SELECT * FROM dbo.sysutility_ucp_health_policies_internal WHERE health_policy_id = @resource_health_policy_id AND is_global_policy = 0)
BEGIN
RAISERROR(22981, -1, -1)
RETURN(1)
END
DELETE dbo.sysutility_ucp_health_policies_internal
WHERE health_policy_id = @resource_health_policy_id
SELECT @retval = @@error
RETURN(@retval)
END
GO
/**********************************************************************/
/* Create procedure sp_sysutility_ucp_update_policy */
/* Updates the resource health policy record with input utilization threshold */
/**********************************************************************/
IF OBJECT_ID ('dbo.sp_sysutility_ucp_update_policy') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_ucp_update_policy]', 0, 1) WITH NOWAIT;
DROP PROCEDURE sp_sysutility_ucp_update_policy
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_ucp_update_policy]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_update_policy]
@resource_health_policy_id INT
, @utilization_threshold INT
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @retval INT
DECLARE @null_column SYSNAME
SET @null_column = NULL
IF (@resource_health_policy_id IS NULL OR @resource_health_policy_id = 0)
SET @null_column = '@resource_health_policy_id'
ELSE IF (@utilization_threshold IS NULL OR @utilization_threshold < 0 OR @utilization_threshold > 100)
SET @null_column = '@utilization_threshold'
IF @null_column IS NOT NULL
BEGIN
RAISERROR(14043, -1, -1, @null_column, 'sp_sysutility_ucp_update_policy')
RETURN(1)
END
IF NOT EXISTS (SELECT * FROM dbo.sysutility_ucp_health_policies_internal WHERE health_policy_id = @resource_health_policy_id)
BEGIN
RAISERROR(22981, -1, -1)
RETURN(1)
END
UPDATE dbo.sysutility_ucp_health_policies_internal
SET utilization_threshold = @utilization_threshold
WHERE health_policy_id = @resource_health_policy_id
SELECT @retval = @@error
RETURN(@retval)
END
GO
/**********************************************************************/
/* Create the sysutility_ucp_policy_check_conditions_internal table */
/* This table contains metadata information to build the check condition */
/* Following are the values supported by each of the below attributes */
/* target_type: Computer - 1, DataFile - 2, LogFile - 3, Server - 4, DeployedDac - 5, Volume - 6 */
/* resource_type: StorageSpace - 1, StorageIO - 2, Processor - 3, Memory - 4, NetworkIO - 5 */
/* utilization_type: UnderUtilization - 1, OverUtilization - 2 */
/* operator_type: = AND - 1, OR - 2, - 3, != - 4, < - 5, > - 6, <= - 7, >= - 8 */
/**********************************************************************/
IF(OBJECT_ID(N'[dbo].[sysutility_ucp_policy_check_conditions_internal]', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table [dbo].[sysutility_ucp_policy_check_conditions_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_policy_check_conditions_internal] (
target_type INT NOT NULL,
resource_type INT NOT NULL,
utilization_type INT NOT NULL,
facet_name SYSNAME NOT NULL,
attribute_name SYSNAME NOT NULL,
operator_type INT NOT NULL,
property_name SYSNAME NOT NULL
CONSTRAINT [PK_sysutility_ucp_policy_check_condition_internal_type] PRIMARY KEY CLUSTERED (resource_type, target_type, utilization_type, facet_name, attribute_name ASC),
);
END
GO
/**********************************************************************/
/* Create the sysutility_ucp_policy_check_conditions */
/**********************************************************************/
IF object_id(N'dbo.sysutility_ucp_policy_check_conditions', 'V') IS NOT NULL
DROP VIEW dbo.sysutility_ucp_policy_check_conditions
GO
CREATE VIEW dbo.sysutility_ucp_policy_check_conditions
AS
SELECT
cc.target_type AS target_type,
cc.resource_type AS resource_type,
cc.utilization_type AS utilization_type,
cc.facet_name AS facet_name,
cc.attribute_name AS attribute_name,
cc.operator_type AS operator_type,
cc.property_name AS property_name
FROM msdb.[dbo].[sysutility_ucp_policy_check_conditions_internal] cc
GO
DELETE FROM msdb.dbo.sysutility_ucp_policy_check_conditions_internal
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(1, 3, 1, 'Computer', 'ProcessorUtilization', 8, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(1, 3, 2, 'Computer', 'ProcessorUtilization', 7, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(2, 1, 1, 'IDataFilePerformanceFacet', 'SpaceUtilization', 8, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(2, 1, 2, 'IDataFilePerformanceFacet', 'SpaceUtilization', 7, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(3, 1, 1, 'ILogFilePerformanceFacet', 'SpaceUtilization', 8, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(3, 1, 2, 'ILogFilePerformanceFacet', 'SpaceUtilization', 7, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(4, 3, 1, 'Server', 'ProcessorUsage', 8, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(4, 3, 2, 'Server', 'ProcessorUsage', 7, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(5, 3, 1, 'DeployedDac', 'ProcessorUtilization', 8, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(5, 3, 2, 'DeployedDac', 'ProcessorUtilization', 7, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(6, 1, 1, 'Volume', 'TotalSpaceUtilization', 8, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_check_conditions_internal VALUES(6, 1, 2, 'Volume', 'TotalSpaceUtilization', 7, 'UtilizationThreshold')
GO
/**********************************************************************/
/* Create the sysutility_ucp_policy_target_conditions_internal table */
/* This table contains metadata information to build the target set condition */
/* Following are the values supported by each of the below attributes */
/* rollup_object_type: DeployedDac - 1, ManagedInstance - 2, Computer - 3 */
/* target_type: Computer - 1, DataFile - 2, LogFile - 3, Server - 4, DeployedDac - 5, Volume - 6 */
/* resource_type: StorageSpace - 1, StorageIO - 2, Processor - 3, Memory - 4, NetworkIO - 5 */
/* utilization_type: UnderUtilization - 1, OverUtilization - 2 */
/* operator_type: = AND - 1, OR - 2, - 3, != - 4, < - 5, > - 6, <= - 7, >= - 8 */
/**********************************************************************/
IF(OBJECT_ID(N'[dbo].[sysutility_ucp_policy_target_conditions_internal]', 'U') IS NULL)
BEGIN
RAISERROR ( 'Creating table [dbo].[sysutility_ucp_policy_target_conditions_internal]', 0, 1) WITH NOWAIT;
CREATE TABLE [dbo].[sysutility_ucp_policy_target_conditions_internal] (
rollup_object_type INT NOT NULL,
target_type INT NOT NULL,
resource_type INT NOT NULL,
utilization_type INT NOT NULL,
facet_name SYSNAME NOT NULL,
attribute_name SYSNAME NOT NULL,
operator_type INT NOT NULL,
property_name SYSNAME NOT NULL
CONSTRAINT [PK_sysutility_ucp_policy_target_condition_internal_type] PRIMARY KEY CLUSTERED (rollup_object_type, resource_type, target_type, utilization_type, facet_name, attribute_name ASC),
);
END
GO
/**********************************************************************/
/* Create the sysutility_ucp_policy_target_conditions */
/**********************************************************************/
IF object_id(N'dbo.sysutility_ucp_policy_target_conditions', 'V') IS NOT NULL
DROP VIEW dbo.sysutility_ucp_policy_target_conditions
GO
CREATE VIEW dbo.sysutility_ucp_policy_target_conditions
AS
SELECT
tc.rollup_object_type AS rollup_object_type,
tc.target_type AS target_type,
tc.resource_type AS resource_type,
tc.utilization_type AS utilization_type,
tc.facet_name AS facet_name,
tc.attribute_name AS attribute_name,
tc.operator_type as operator_type,
tc.property_name as property_name
FROM msdb.[dbo].[sysutility_ucp_policy_target_conditions_internal] tc
GO
DELETE FROM msdb.dbo.sysutility_ucp_policy_target_conditions_internal
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(1, 5, 3, 0, 'DeployedDac', 'ServerInstanceName', 3, 'DacServerInstanceName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(1, 5, 3, 0, 'DeployedDac', 'Name', 3, 'DacName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(1, 5, 3, 1, 'DeployedDac', 'ProcessorUtilization', 5, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(1, 5, 3, 2, 'DeployedDac', 'ProcessorUtilization', 6, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(1, 2, 1, 0, 'Server', 'InstanceName', 3, 'DacInstanceName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(1, 2, 1, 0, 'Server', 'NetName', 3, 'DacComputerName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(1, 2, 1, 0, 'Database', 'Name', 3, 'DacDatabaseName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(1, 3, 1, 0, 'Server', 'InstanceName', 3, 'DacInstanceName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(1, 3, 1, 0, 'Server', 'NetName', 3, 'DacComputerName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(1, 3, 1, 0, 'Database', 'Name', 3, 'DacDatabaseName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(2, 4, 3, 0, 'Server', 'InstanceName', 3, 'ServerInstanceName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(2, 4, 3, 0, 'Server', 'NetName', 3, 'ServerNetName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(2, 4, 3, 1, 'Server', 'ProcessorUsage', 5, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(2, 4, 3, 2, 'Server', 'ProcessorUsage', 6, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(2, 2, 1, 0, 'Server', 'InstanceName', 3, 'ServerInstanceName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(2, 2, 1, 0, 'Server', 'NetName', 3, 'ServerNetName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(2, 3, 1, 0, 'Server', 'InstanceName', 3, 'ServerInstanceName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(2, 3, 1, 0, 'Server', 'NetName', 3, 'ServerNetName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(3, 1, 3, 0, 'Computer', 'Name', 3, 'ComputerName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(3, 1, 3, 1, 'Computer', 'ProcessorUtilization', 5, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(3, 1, 3, 2, 'Computer', 'ProcessorUtilization', 6, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(3, 6, 1, 0, 'Computer', 'Name', 3, 'ComputerName')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(3, 6, 1, 1, 'Volume', 'TotalSpaceUtilization', 5, 'UtilizationThreshold')
GO
INSERT INTO msdb.dbo.sysutility_ucp_policy_target_conditions_internal VALUES(3, 6, 1, 2, 'Volume', 'TotalSpaceUtilization', 6, 'UtilizationThreshold')
GO
/**********************************************************************/
/* Create table sysutility_ucp_policy_violations_internal */
/* This table stores violations for health polices from latest policy evaluation */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_policy_violations_internal', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table dbo.sysutility_ucp_policy_violations_internal', 0, 1) WITH NOWAIT;
CREATE TABLE sysutility_ucp_policy_violations_internal
(
health_policy_id INT NOT NULL,
policy_id INT NOT NULL,
policy_name SYSNAME NULL,
history_id INT NOT NULL,
detail_id INT NOT NULL,
target_query_expression NVARCHAR(MAX) NULL,
target_query_expression_with_id NVARCHAR(MAX) NULL,
execution_date DATETIME NULL,
result INT NULL,
CONSTRAINT [PK_sysutility_ucp_policy_violations_internal]
PRIMARY KEY CLUSTERED (policy_id, history_id, detail_id)
)
END
GO
/**********************************************************************/
/* Create the health policy violations view */
/* This view fetches violations for health polices from latest policy evaluation */
/**********************************************************************/
IF object_id(N'dbo.sysutility_ucp_policy_violations', 'V') IS NOT NULL
DROP VIEW dbo.sysutility_ucp_policy_violations
GO
CREATE VIEW dbo.sysutility_ucp_policy_violations
AS
SELECT pv.health_policy_id
, pv.policy_id
, pv.policy_name
, pv.history_id
, pv.detail_id
, pv.target_query_expression
, pv.target_query_expression_with_id
, pv.execution_date
, pv.result
FROM dbo.sysutility_ucp_policy_violations_internal pv
GO
/**********************************************************************/
/* Create procedure sp_sysutility_ucp_get_policy_violations */
/* This SP is used to fetch the violations for health polices from */
/* latest policy evaluation and cache them in the intermediate table */
/**********************************************************************/
IF OBJECT_ID ('dbo.sp_sysutility_ucp_get_policy_violations') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_get_policy_violations', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_get_policy_violations
END;
GO
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_get_policy_violations', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_get_policy_violations
WITH EXECUTE AS OWNER
AS
BEGIN
-- Clear the existing policy violations
TRUNCATE TABLE dbo.sysutility_ucp_policy_violations_internal
-- Cache the latest policy violations for non-volatile resources
-- The health state for non-volatile resource is determined based on
-- the latest policy violation against the target (file, volume) type.
INSERT INTO dbo.sysutility_ucp_policy_violations_internal
SELECT p.health_policy_id
, p.policy_id
, p.policy_name
, d.history_id
, d.detail_id
, d.target_query_expression
, d.target_query_expression_with_id
, d.execution_date
, d.result
FROM msdb.dbo.sysutility_ucp_policies p
INNER JOIN msdb.dbo.syspolicy_policy_execution_history_internal h
ON h.policy_id = p.policy_id
INNER JOIN msdb.dbo.syspolicy_policy_execution_history_details_internal d
ON d.history_id = h.history_id
WHERE p.resource_type = 1 -- Filter non-volatile resources (currently storage type only)
-- PBM stores the end_date in local time so convert the 'latest_processing_time' datetimeoffset to local datetime before compare
AND h.end_date >= (SELECT CONVERT(DATETIME, latest_processing_time) FROM [msdb].[dbo].[sysutility_ucp_processing_state_internal])
AND h.is_full_run = 1
AND h.result = 0
AND d.result = 0;
-- Get the policy evaluation count for volatile resources over the trailing window.
-- The health state for volatile resource is determined based on the policy
-- violation against the target (cpu) type over a trailing window and should
-- exeed the occurrence frequency percent. E.g. a tartget can be considered
-- as over utilized if its violating the policy for last 3 out of 4 evaluations
-- (1 hour trailing window and 70 % occurrence frequency)
SELECT p.policy_id
, MAX(h.end_date) execution_date
, CASE WHEN 0 = COUNT(*) THEN 1 ELSE COUNT(*) END AS evaluation_count
, p.utilization_type
, p.health_policy_id
, p.policy_name
, pc.occurence_frequency
INTO #policy_evaluations
FROM msdb.dbo.sysutility_ucp_policies p
INNER JOIN msdb.dbo.syspolicy_policy_execution_history_internal h
ON p.policy_id = h.policy_id
INNER JOIN msdb.dbo.sysutility_ucp_policy_configuration pc
ON p.utilization_type = pc.utilization_type
WHERE h.end_date >= DATEADD(MI, -60*pc.trailing_window, CURRENT_TIMESTAMP)
AND h.is_full_run = 1
AND p.resource_type = 3 -- Filter volatile resources (currently cpu type only)
GROUP BY p.policy_id
, p.utilization_type
, p.health_policy_id
, p.policy_name
, pc.occurence_frequency;
-- Get the policy violation count for the target types over the trailing window
-- Note:
-- 1. If the trailing window is size increased, this computation will continue to
-- use the exiting violations in the history against the newly configured window size.
-- It will only be effective after the full trailing window size is reached.
-- 2. If the occurrence frequency is changed, it will be effective in the next run of the
-- health state computation.
SELECT p.policy_id
, d.target_query_expression
, COUNT(*) AS violation_count
, MAX(h.history_id) as history_id
, MAX(d.detail_id) AS detail_id
INTO #policy_violations
FROM msdb.dbo.sysutility_ucp_policies p
INNER JOIN msdb.dbo.syspolicy_policy_execution_history_internal h
ON p.policy_id = h.policy_id
INNER JOIN msdb.dbo.syspolicy_policy_execution_history_details_internal d
ON d.history_id = h.history_id
INNER JOIN msdb.dbo.sysutility_ucp_policy_configuration pc
ON p.utilization_type = pc.utilization_type
WHERE h.end_date >= DATEADD(MI, -60*pc.trailing_window, CURRENT_TIMESTAMP)
AND h.is_full_run = 1
AND h.result = 0
AND d.result = 0
AND p.resource_type = 3 -- Filter volatile resources (currently cpu type only)
GROUP BY p.policy_id, d.target_query_expression;
INSERT INTO dbo.sysutility_ucp_policy_violations_internal
SELECT pe.health_policy_id
, pe.policy_id
, pe.policy_name
, pv.history_id
, pv.detail_id
, pv.target_query_expression
, N'' AS target_query_expression_with_id
, pe.execution_date
, 0 AS result
FROM #policy_evaluations pe
INNER JOIN #policy_violations pv
ON pe.policy_id = pv.policy_id
WHERE pe.occurence_frequency <= ((pv.violation_count * 100) / pe.evaluation_count);
END
GO
--**********************************************************************
-- Create function fn_encode_sqlname_for_powershell
-- Function description:
-- Encodes the sql names making it suitable for powershell representation
-- This is required as some of the characters conflict with PS commands
-- More details: http://msdn.microsoft.com/en-us/library/cc281841.aspx
--Parameter description:
--1. @sql_name - the sql name that needs encoding
--*********************************************************************
IF(OBJECT_ID(N'dbo.fn_encode_sqlname_for_powershell', 'FN') IS NOT NULL)
BEGIN
RAISERROR ('Dropping function dbo.fn_encode_sqlname_for_powershell', 0, 1) WITH NOWAIT;
DROP FUNCTION dbo.fn_encode_sqlname_for_powershell
END
GO
RAISERROR ('Creating function dbo.fn_encode_sqlname_for_powershell', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION dbo.fn_encode_sqlname_for_powershell
(
@sql_name SYSNAME
)
RETURNS SYSNAME
AS
BEGIN
DECLARE @encoded_name SYSNAME = @sql_name
SET @encoded_name = REPLACE(@encoded_name, N'%', N'%25')
SET @encoded_name = REPLACE(@encoded_name, N'\', N'%5C')
SET @encoded_name = REPLACE(@encoded_name, N'/', N'%2F')
SET @encoded_name = REPLACE(@encoded_name, N':', N'%3A')
SET @encoded_name = REPLACE(@encoded_name, N'<', N'%3C')
SET @encoded_name = REPLACE(@encoded_name, N'>', N'%3E')
SET @encoded_name = REPLACE(@encoded_name, N'*', N'%2A')
SET @encoded_name = REPLACE(@encoded_name, N'?', N'%3F')
SET @encoded_name = REPLACE(@encoded_name, N'[', N'%5B')
SET @encoded_name = REPLACE(@encoded_name, N']', N'%5D')
SET @encoded_name = REPLACE(@encoded_name, N'|', N'%7C')
RETURN @encoded_name
END
GO
--**********************************************************************
-- Create procedure sp_sysutility_ucp_delete_policy_history
-- Procedure description:
-- This SP purges the utility resource health policy evaluation results history and details
-- For volatile resources, it deletes the records older than the specified trailing window time frame
-- For non-volatile resources, it deletes the records older than the current processing time
-- Since this SP deletes (many) records, it could possibly affect the performance due to impact on indexes
-- We should consider droping and recreating the indexes if the purged records are huge in number.
--**********************************************************************
IF OBJECT_ID ('dbo.sp_sysutility_ucp_delete_policy_history') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_delete_policy_history', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_delete_policy_history
END;
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_delete_policy_history', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_delete_policy_history
WITH EXECUTE AS OWNER
AS
BEGIN
SET NOCOUNT ON;
DECLARE @over_utilization_trailing_window INT = 1
DECLARE @under_utilization_trailing_window INT = 1
DECLARE @rows_affected bigint;
DECLARE @delete_batch_size int;
-- As we delete the master record in the history table which cascades
-- to foreign key records in details table; keep the delete batch size to 100.
SET @delete_batch_size = 100;
SET @rows_affected = -1;
-- Get the configured over utilization trailing window
SELECT @over_utilization_trailing_window = CAST(ci.current_value AS INT)
FROM msdb.dbo.sysutility_ucp_configuration_internal ci
WHERE ci.name = 'OverUtilizationTrailingWindow'
-- Get the configured under utilization trailing window
SELECT @under_utilization_trailing_window = CAST(ci.current_value AS INT)
FROM msdb.dbo.sysutility_ucp_configuration_internal ci
WHERE ci.name = 'UnderUtilizationTrailingWindow'
-- Purge volatile resource policy evaluation history against over utilization trailing window
DECLARE @max_end_date datetime;
SET @max_end_date = DATEADD(HH, -@over_utilization_trailing_window, CURRENT_TIMESTAMP);
SET @rows_affected = -1;
WHILE (@rows_affected != 0)
BEGIN
-- We use sp_executesql here because the values of @delete_batch_size and @max_end_date could
-- influence plan selection. These are variables that have unknown values when the plan for the
-- proc is compiled. By deferring compilation until the variables have taken on their final values,
-- we give the optimizer information that it needs to choose the best possible plan. We could also
-- use an OPTION(RECOMPILE) hint to accomplish the same thing, but the sp_executesql approach avoids
-- paying the plan compile cost for each loop iteration.
EXEC sp_executesql N'
DELETE TOP (@delete_batch_size) h
FROM msdb.dbo.syspolicy_policy_execution_history_internal h
INNER JOIN msdb.dbo.sysutility_ucp_policies p ON p.policy_id = h.policy_id
WHERE p.resource_type = 3 -- processor resource type
AND p.utilization_type = 2 -- over-utilization
AND h.end_date < @max_end_date',
N'@delete_batch_size int, @max_end_date datetime',
@delete_batch_size = @delete_batch_size, @max_end_date = @max_end_date;
SET @rows_affected = @@ROWCOUNT;
END;
-- Purge volatile resource policy evaluation history against under utilization trailing window
SET @max_end_date = DATEADD(HH, -@under_utilization_trailing_window, CURRENT_TIMESTAMP);
SET @rows_affected = -1;
WHILE (@rows_affected != 0)
BEGIN
EXEC sp_executesql N'
DELETE TOP (@delete_batch_size) h
FROM msdb.dbo.syspolicy_policy_execution_history_internal h
INNER JOIN msdb.dbo.sysutility_ucp_policies p ON p.policy_id = h.policy_id
WHERE p.resource_type = 3 -- processor resource type
AND p.utilization_type = 1 -- under-utilization
AND h.end_date < @max_end_date',
N'@delete_batch_size int, @max_end_date datetime',
@delete_batch_size = @delete_batch_size, @max_end_date = @max_end_date;
SET @rows_affected = @@ROWCOUNT;
END;
-- Purge non-volatile resource policy evaluation history older than the current processing_time recorded
-- The latest policy evaluation results are not purged to avoid potential conflicts with the health
-- state computation running simultaneoulsy in the caching (master) job during the same time schedule.
SET @rows_affected = -1;
-- PBM stores the end_date in local time so convert the 'latest_processing_time' datetimeoffset to a local datetime
SELECT @max_end_date = CONVERT(DATETIME, latest_processing_time) FROM [msdb].[dbo].[sysutility_ucp_processing_state_internal];
WHILE (@rows_affected != 0)
BEGIN
EXEC sp_executesql N'
DELETE TOP (@delete_batch_size) h
FROM msdb.dbo.syspolicy_policy_execution_history_internal h
INNER JOIN msdb.dbo.sysutility_ucp_policies p ON p.policy_id = h.policy_id
WHERE p.resource_type = 1 -- storage space resource type
AND h.end_date < @max_end_date',
N'@delete_batch_size int, @max_end_date datetime',
@delete_batch_size = @delete_batch_size, @max_end_date = @max_end_date;
SET @rows_affected = @@ROWCOUNT;
END;
END
GO
--**********************************************************************
-- Create function fn_sysutility_ucp_get_global_health_policy
-- Function description:
-- Identifies the global policy for a given object type
-- 1. Check if there is a global policy for that object type in a target type
-- 2. Check if there is a global policy for that object type at utility level
-- Parameter description:
-- 1. @rollup_object_type - type of the object (0: global, 1: dac, 2: server)
-- 2. @target_type - target resource object type (e.g. file, logfile, volume, computer etc)
-- 3. @resource_type - type of resource monitored (1: storage space, 2: storage I/O, 3: processor, 4: memory, 5: network I/O)
-- 4. @utilization_type - type of the utilization (1: under utilization, 2: over utilization)
--**********************************************************************
IF(OBJECT_ID(N'dbo.[fn_sysutility_ucp_get_global_health_policy]', 'FN') IS NOT NULL)
BEGIN
RAISERROR ('Dropping function dbo.[fn_sysutility_ucp_get_global_health_policy]', 0, 1) WITH NOWAIT;
DROP FUNCTION dbo.[fn_sysutility_ucp_get_global_health_policy]
END
GO
RAISERROR ('Creating function dbo.[fn_sysutility_ucp_get_global_health_policy]', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION dbo.[fn_sysutility_ucp_get_global_health_policy](
@rollup_object_type INT
, @target_type INT
, @resource_type INT
, @utilization_type INT )
RETURNS INT
AS
BEGIN
DECLARE @health_policy_id INT
-- Check if there is a global policy for that object type in a target type
SELECT @health_policy_id = hp.health_policy_id
FROM msdb.dbo.sysutility_ucp_policies hp
WHERE hp.rollup_object_type = @rollup_object_type
AND hp.target_type = @target_type
AND hp.resource_type = @resource_type
AND hp.utilization_type = @utilization_type
AND hp.is_global_policy = 1
-- If not found, check if there is a global policy for that object type at utility level.
-- This is the last resort, must find the global policy here.
IF @health_policy_id = 0 OR @health_policy_id IS NULL
BEGIN
SELECT @health_policy_id = hp.health_policy_id
FROM msdb.dbo.sysutility_ucp_policies hp
WHERE hp.rollup_object_type = 0
AND hp.target_type = @target_type
AND hp.resource_type = @resource_type
AND hp.utilization_type = @utilization_type
AND hp.is_global_policy = 1
END
RETURN @health_policy_id
END
GO
--**********************************************************************
--**********************************************************************
-- Create function fn_sysutility_ucp_get_applicable_policy
-- Function description:
-- Identifies the applciable policy for a given object represented by URN
-- 1. Checking if there is an overridden policy for that object
-- 2. Checking if there is a global policy for that object type
-- Parameter description:
-- 1. @rollup_object_urn - urn of the object
-- 2. @rollup_object_type - type of the object (0: global, 1: dac, 2: server)
-- 3. @target_type - target resource object type (e.g. file, logfile, volume, computer etc)
-- 4. @resource_type - type of resource monitored (1: storage space, 2: storage I/O, 3: processor, 4: memory, 5: network I/O)
-- 5. @utilization_type - type of the utilization (1: under utilization, 2: over utilization)
--**********************************************************************
IF(OBJECT_ID(N'dbo.[fn_sysutility_ucp_get_applicable_policy]', 'FN') IS NOT NULL)
BEGIN
RAISERROR ('Dropping function dbo.[fn_sysutility_ucp_get_applicable_policy]', 0, 1) WITH NOWAIT;
DROP FUNCTION dbo.[fn_sysutility_ucp_get_applicable_policy]
END
GO
RAISERROR ('Creating function dbo.[fn_sysutility_ucp_get_applicable_policy]', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION dbo.[fn_sysutility_ucp_get_applicable_policy](
@rollup_object_urn NVARCHAR(4000)
, @rollup_object_type INT
, @target_type INT
, @resource_type INT
, @utilization_type INT )
RETURNS INT
AS
BEGIN
DECLARE @health_policy_id INT
-- Check if there is an overridden policy for the rollup object
SELECT @health_policy_id = hp.health_policy_id
FROM msdb.dbo.sysutility_ucp_policies hp
WHERE hp.rollup_object_urn = @rollup_object_urn
AND hp.rollup_object_type = @rollup_object_type
AND hp.target_type = @target_type
AND hp.resource_type = @resource_type
AND hp.utilization_type = @utilization_type
-- If no overridden policy exist, get the global policy
-- Check if the specific rollup_object has the global policy
IF @health_policy_id = 0 OR @health_policy_id IS NULL
BEGIN
SELECT @health_policy_id = msdb.dbo.fn_sysutility_ucp_get_global_health_policy(@rollup_object_type
, @target_type
, @resource_type
, @utilization_type)
END
RETURN @health_policy_id
END
GO
/**********************************************************************/
/* Create function fn_sysutility_ucp_get_aggregated_failure_count */
/**********************************************************************/
IF(OBJECT_ID(N'[dbo].[fn_sysutility_ucp_get_aggregated_failure_count]', 'FN') IS NOT NULL)
BEGIN
RAISERROR ('Dropping function [fn_sysutility_ucp_get_aggregated_failure_count]', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysutility_ucp_get_aggregated_failure_count]
END
GO
RAISERROR ('Creating function [fn_sysutility_ucp_get_aggregated_failure_count]', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_ucp_get_aggregated_failure_count](@policy_name SYSNAME, @target_query_expression NVARCHAR(max))
RETURNS INT
AS
BEGIN
DECLARE @count INT
SET @count = 0;
SELECT @count = COUNT(hs.result)
FROM msdb.dbo.sysutility_ucp_policy_violations hs
INNER JOIN msdb.dbo.syspolicy_policies p ON hs.policy_id = p.policy_id
WHERE (hs.target_query_expression_with_id LIKE +'%'+@target_query_expression+'%' ESCAPE '\'
OR hs.target_query_expression LIKE +'%'+@target_query_expression+'%')
AND hs.result = 0
AND p.name = @policy_name
RETURN @count
END
GO
/**********************************************************************/
/* Create function fn_sysutility_ucp_get_policy_violations */
/**********************************************************************/
IF(OBJECT_ID(N'[dbo].[fn_sysutility_ucp_get_policy_violations]', 'TF') IS NOT NULL)
BEGIN
RAISERROR ('Dropping function [fn_sysutility_ucp_get_policy_violations]', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysutility_ucp_get_policy_violations]
END
GO
RAISERROR ('Creating function [fn_sysutility_ucp_get_policy_violations]', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_ucp_get_policy_violations](@policy_name SYSNAME, @target_query_expression NVARCHAR(max))
RETURNS @data TABLE
( health_state_id BIGINT )
AS
BEGIN
INSERT INTO @data
SELECT hs.detail_id
FROM msdb.dbo.sysutility_ucp_policy_violations hs
INNER JOIN msdb.dbo.syspolicy_policies p ON hs.policy_id = p.policy_id
WHERE (hs.target_query_expression_with_id LIKE +'%'+@target_query_expression+'%' ESCAPE '\'
OR hs.target_query_expression LIKE +'%'+@target_query_expression+'%')
AND hs.result = 0
AND p.name = @policy_name
RETURN
END
GO
/********************************************************************************/
/********************************************************************************/
/* Create function [fn_sysutility_ucp_get_file_space_utilization_history] which returns */
/* a table containing storage utilization history */
-- @object_type :
-- 0 --> Utility-level
-- 1 --> Server (computer) level
-- 2 --> Volume level
-- 3 --> Instance level
-- 4 --> Database level
-- 5 --> Filegroup level
-- 6 --> DataFile level
-- 7 --> LogFile level
-- @virtual_server_name: virtual computer name
-- (logical name for the failover cluster if this is part of a cluster)
-- otherwise, the name of the standalone computer
-- @volume_device_id: device_id of the volume
-- @server_instance_name: SQL instance name (server-qualified name)
-- @database_name: Name of the database
-- @filegroup_name: name of the filegroup
-- @dbfile_name: Name of the datafile/logfile
-- @start_time : starting time for interval
-- @end_time : end time for the interval
-- @aggregation_interval: This attribute is helpful setting starttime for the timespan.
-- 1 --> No aggregation (raw data)
-- 2 --> Hourly aggregation
-- 3 --> Daily aggregation
--
-- NOTE: total_space_bytes may be NULL for database, filegroup, instance objects.
-- We treat that as equivalent to 0 for the purposes of this function, although
-- it's not entirely clear that that's appropriate.
/********************************************************************************/
IF(OBJECT_ID(N'[dbo].[fn_sysutility_ucp_get_file_space_utilization_history]') IS NOT NULL)
BEGIN
RAISERROR ('Dropping function [fn_sysutility_ucp_get_file_space_utilization_history]', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysutility_ucp_get_file_space_utilization_history]
END
GO
RAISERROR ('Creating function [fn_sysutility_ucp_get_file_space_utilization_history]', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_ucp_get_file_space_utilization_history](
@object_type TINYINT,
@virtual_server_name SYSNAME,
@volume_device_id SYSNAME,
@server_instance_name SYSNAME,
@database_name SYSNAME,
@filegroup_name SYSNAME,
@database_file_name SYSNAME,
@start_time DATETIMEOFFSET(7),
@end_time DATETIMEOFFSET(7),
@aggregation_interval TINYINT
)
RETURNS TABLE AS RETURN (
SELECT CASE WHEN ISNULL(total_space_bytes, 0) = 0 THEN 0 ELSE (used_space_bytes * 100)/total_space_bytes END AS storage_utilization_percent,
CONVERT(BIGINT, used_space_bytes) AS storage_utilization_in_bytes,
CONVERT(BIGINT, ISNULL(total_space_bytes, 0)) AS storage_capacity_in_bytes,
processing_time as sample_time
FROM dbo.syn_sysutility_ucp_space_utilization
WHERE @object_type = object_type AND
@aggregation_interval = aggregation_type AND
(processing_time BETWEEN @start_time AND @end_time) AND
ISNULL(@virtual_server_name, '') = virtual_server_name AND
ISNULL(@volume_device_id, '') = volume_device_id AND
ISNULL(@server_instance_name, '') = server_instance_name AND
ISNULL(@database_name, '') = database_name AND
ISNULL(@filegroup_name, '') = [filegroup_name] AND
ISNULL(@database_file_name, '') = [dbfile_name]
)
GO
/********************************************************************************/
/* Create function [fn_sysutility_ucp_get_cpu_utilization_history] which returns */
/* a table containing processor utilization history */
-- @object_type :
-- 1 --> Server (computer) level
-- 2 --> Instance level
-- 3 --> Database level (DAC)
-- @physical_server_name: (physical) computer name
-- @server_instance_name: SQL instance name (server-qualified name)
-- @dac_name: Name of the DAC instance (also the database_name)
-- @start_time : starting time for interval
-- @end_time : end time for the interval
-- @aggregation_interval: This attribute is helpful setting starttime for the timespan.
-- 1 --> No aggregation (raw data)
-- 2 --> Hourly aggregation
-- 3 --> Daily aggregation
/********************************************************************************/
IF(OBJECT_ID(N'[dbo].[fn_sysutility_ucp_get_cpu_utilization_history]') IS NOT NULL)
BEGIN
RAISERROR ('Dropping function [fn_sysutility_ucp_get_cpu_utilization_history]', 0, 1) WITH NOWAIT;
DROP FUNCTION [dbo].[fn_sysutility_ucp_get_cpu_utilization_history]
END
GO
RAISERROR ('Creating function [fn_sysutility_ucp_get_cpu_utilization_history]', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_ucp_get_cpu_utilization_history](
@object_type TINYINT,
@physical_server_name SYSNAME,
@server_instance_name SYSNAME,
@dac_name SYSNAME,
@start_time DATETIMEOFFSET(7),
@end_time DATETIMEOFFSET(7),
@aggregation_interval TINYINT
)
RETURNS TABLE
AS
RETURN (
SELECT percent_total_cpu_utilization AS processor_utilization_percent,
processing_time AS sample_time
FROM dbo.syn_sysutility_ucp_cpu_utilization
WHERE @object_type = object_type AND
@aggregation_interval = aggregation_type AND
(processing_time BETWEEN @start_time AND @end_time) AND
ISNULL(@physical_server_name, '') = physical_server_name AND
ISNULL(@server_instance_name, '') = server_instance_name AND
ISNULL(@dac_name, '') = database_name
)
GO
--------------------------------------------------------------------------------------------------
-- View that exposes the latest properties for all installed DACs.
-- This view wraps a synonym that gets redirected to a MDW table after sysutility_mdw is created.
--------------------------------------------------------------------------------------------------
IF OBJECT_ID(N'[dbo].[sysutility_ucp_deployed_dacs]', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_deployed_dacs]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_deployed_dacs];
END;
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_deployed_dacs]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_deployed_dacs
AS
SELECT
dacs.dac_id, -- todo (VSTS #345036): This column will be removed
dacs.dac_name,
dacs.dac_deploy_date AS dac_deployed_date,
dacs.dac_description AS dac_description,
dacs.dac_percent_total_cpu_utilization AS dac_percent_total_cpu_utilization,
dacs.server_instance_name AS dac_server_instance_name,
dacs.physical_server_name AS dac_physical_server_name,
dacs.batch_time AS dac_collection_time,
dacs.processing_time AS dac_processing_time,
dacs.urn,
dacs.powershell_path
FROM dbo.syn_sysutility_ucp_dacs as dacs
--- The join operator removes those DACs in the managed instances which are unenrolled during
--- the time between two consecutive data collection.
--- See VSTS #473462 for more information
INNER JOIN dbo.sysutility_ucp_managed_instances as mis
ON dacs.server_instance_name = mis.instance_name;
GO
/**********************************************************************/
/* create the computer object view that utilizes the data collected */
/* in the MDW */
/* */
/* We keep track of two names here - the "physical_server_name" and */
/* the "virtual_server_name". In most cases, these two have the same */
/* value. However, in the case of failover-cluster-instances, the */
/* virtual_server_name refers to the logical name for the cluster, */
/* while the physical_server_name refers to the name of the computer */
/* within that cluster. */
/* In general, we use physical_server_name across the board, except */
/* for "shared" resources like space-utilization, where the virtual */
/* name is more appropriate */
/**********************************************************************/
IF OBJECT_ID(N'dbo.sysutility_ucp_computers', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_computers]', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_computers;
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_computers]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_computers
AS
SELECT
server_table.id AS computer_id -- todo (VSTS #345036): This column will be removed
, server_table.virtual_server_name AS virtual_server_name
, server_table.physical_server_name AS physical_server_name
, server_table.is_clustered_server AS is_clustered
, server_table.percent_total_cpu_utilization AS processor_utilization
, server_table.cpu_name AS cpu_name
, server_table.cpu_max_clock_speed AS cpu_max_clock_speed
, server_table.processing_time AS processing_time
, urn
, powershell_path
FROM [dbo].[syn_sysutility_ucp_computers] as server_table
GO
-- =============================================
-- Create View : sysutility_ucp_volumes
-- =============================================
IF OBJECT_ID(N'dbo.sysutility_ucp_volumes', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_volumes]', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_volumes
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_volumes]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_volumes
AS
SELECT
[ID] AS volume_id -- todo (VSTS #345036): This column will be removed
, physical_server_name AS physical_server_name
, virtual_server_name AS virtual_server_name
, volume_name
, volume_device_id
, powershell_path
, total_space_available AS total_space
, total_space_utilized AS total_space_used
, percent_total_space_utilization AS total_space_utilization
FROM dbo.syn_sysutility_ucp_volumes;
GO
-- =============================================
-- Create View : sysutility_ucp_utility_space_utilization
-- =============================================
IF OBJECT_ID(N'dbo.sysutility_ucp_utility_space_utilization', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_utility_space_utilization]', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_utility_space_utilization
END;
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_utility_space_utilization]', 0, 1) WITH NOWAIT;
GO
---
--- Gets the total utility space utilization.
--- The funny left-outer-join is to account for cases where there is no "utility-wide" entry yet
--- typically, right at bootstrap time
---
CREATE VIEW dbo.sysutility_ucp_utility_space_utilization
AS
SELECT ISNULL(S2.total_space_bytes, 0) AS total_utility_storage,
ISNULL(S2.used_space_bytes, 0) AS total_utilized_space
FROM (SELECT 1 AS x) AS S1
LEFT OUTER JOIN
(SELECT total_space_bytes, used_space_bytes
FROM dbo.syn_sysutility_ucp_space_utilization
WHERE object_type = 0 AND -- utility-wide information
aggregation_type = 0 AND -- detail-information
processing_time = (SELECT latest_processing_time FROM msdb.dbo.sysutility_ucp_processing_state_internal)
) AS S2 ON (1=1)
GO
-- =============================================
-- Create View : [sysutility_ucp_instances]
-- All of the properties are auto-generated using the below select statement
-- select ', [' +property_name+']' from [msdb].[dbo].[sysutility_mi_smo_property_configurations_internal] where object_type = 1
-- =============================================
IF OBJECT_ID(N'dbo.sysutility_ucp_instances', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_instances]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_instances]
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_instances]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_instances
AS
SELECT [urn]
, [powershell_path]
, [processing_time]
, [batch_time] AS [collection_time]
, [AuditLevel]
, [BackupDirectory]
, [BrowserServiceAccount]
, [BrowserStartMode]
, [BuildClrVersionString]
, [BuildNumber]
, [Collation]
, [CollationID]
, [ComparisonStyle]
, [ComputerNamePhysicalNetBIOS]
, [DefaultFile]
, [DefaultLog]
, [Edition]
, [EngineEdition]
, [ErrorLogPath]
, [FilestreamShareName]
, [InstallDataDirectory]
, [InstallSharedDirectory]
, [InstanceName]
, [IsCaseSensitive]
, [IsClustered]
, [IsFullTextInstalled]
, [IsSingleUser]
, [Language]
, [MailProfile]
, [MasterDBLogPath]
, [MasterDBPath]
, [MaxPrecision]
, [Name]
, [NamedPipesEnabled]
, [NetName]
, [NumberOfLogFiles]
, [OSVersion]
, [PerfMonMode]
, [PhysicalMemory]
, [Platform]
, [Processors]
, [ProcessorUsage]
, [Product]
, [ProductLevel]
, [ResourceVersionString]
, [RootDirectory]
, [ServerType]
, [ServiceAccount]
, [ServiceInstanceId]
, [ServiceName]
, [ServiceStartMode]
, [SqlCharSet]
, [SqlCharSetName]
, [SqlDomainGroup]
, [SqlSortOrder]
, [SqlSortOrderName]
, [Status]
, [TapeLoadWaitTime]
, [TcpEnabled]
, [VersionMajor]
, [VersionMinor]
, [VersionString]
FROM dbo.syn_sysutility_ucp_smo_servers;
GO
-- =============================================
-- Create View : [sysutility_ucp_databases]
-- All of the properties are auto-generated using the below select statement
-- select ', [' +property_name+']' from [msdb].[dbo].[sysutility_mi_smo_properties_to_collect_internal] where object_type = 2
-- =============================================
IF OBJECT_ID(N'[dbo].[sysutility_ucp_databases]', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_databases]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_databases]
END;
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_databases]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_databases
AS
SELECT S.urn
, S.parent_urn
, S.Collation
, S.CompatibilityLevel
, S.CreateDate
, S.EncryptionEnabled
, S.Name
, S.server_instance_name
, S.powershell_path
, S.RecoveryModel
, [S].[Trustworthy]
, [S].processing_time
, S.state
FROM [dbo].[syn_sysutility_ucp_databases] AS S
GO
-- =============================================
-- Create View : [sysutility_ucp_filegroups]
-- All of the properties are auto-generated using the below select statement
-- select ', [' +property_name+']' from [msdb].[dbo].[sysutility_mi_smo_properties_to_collect_internal] where object_type = 4
-- =============================================
IF OBJECT_ID(N'[dbo].[sysutility_ucp_filegroups]', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_filegroups]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_filegroups]
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_filegroups]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_filegroups
AS
SELECT [S].[urn]
, [S].[parent_urn]
, [S].[Name]
, [S].[server_instance_name]
, [S].[database_name]
, [S].[powershell_path]
, [S].[processing_time]
FROM [dbo].[syn_sysutility_ucp_filegroups] S
GO
-- =============================================
-- Create View : [sysutility_ucp_datafiles]
-- All of the properties are auto-generated using the below select statement
-- select ', [' +property_name+']' from [msdb].[dbo].[sysutility_mi_smo_properties_to_collect_internal] where object_type = 5
-- =============================================
IF OBJECT_ID(N'[dbo].[sysutility_ucp_datafiles]', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_datafiles]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_datafiles]
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_datafiles]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_datafiles
AS
SELECT [S].[urn]
, [S].[parent_urn]
, [S].[Growth]
, [S].[GrowthType]
, [S].[MaxSize]
, [S].[Name]
, [S].[Size]
, [S].[UsedSpace]
, [S].[FileName]
, [S].[VolumeFreeSpace]
, [S].[server_instance_name]
, [S].[database_name]
, [S].[filegroup_name]
, [S].[powershell_path]
, [S].[volume_name]
, [S].[volume_device_id]
, [S].[physical_server_name]
, [S].[available_space] -- in bytes
, CASE WHEN [S].[available_space] = 0.0 THEN 0.0 ELSE ([S].[UsedSpace] * 100)/[S].[available_space] END AS percent_utilization
, [S].[processing_time]
FROM [dbo].[syn_sysutility_ucp_datafiles] S
GO
-- =============================================
-- Create View : [sysutility_ucp_logfiles]
-- All of the properties are auto-generated using the below select statement
-- select ', [' +property_name+']' from [msdb].[dbo].[sysutility_mi_smo_properties_to_collect_internal] where object_type = 3
-- =============================================
IF OBJECT_ID(N'[dbo].[sysutility_ucp_logfiles]', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_logfiles]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_logfiles]
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_logfiles]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_logfiles
AS
SELECT [S].[urn]
, [S].[parent_urn]
, [S].[Growth]
, [S].[GrowthType]
, [S].[MaxSize]
, [S].[Name]
, [S].[Size]
, [S].[UsedSpace]
, [S].[FileName]
, [S].[VolumeFreeSpace]
, [S].[server_instance_name]
, [S].[database_name]
, [S].[powershell_path]
, [S].[volume_name]
, [S].[volume_device_id]
, [S].[physical_server_name]
, [S].[available_space] -- in bytes
, CASE WHEN [S].[available_space] = 0.0 THEN 0.0 ELSE ([S].[UsedSpace] * 100)/[S].[available_space] END AS percent_utilization
, [S].[processing_time]
FROM [dbo].[syn_sysutility_ucp_logfiles] S
GO
-- =============================================
-- Create View : [sysutility_ucp_database_files]
-- Simple (union) view over sysutility_ucp_datafiles and sysutility_ucp_logfiles
-- =============================================
IF OBJECT_ID(N'[dbo].[sysutility_ucp_database_files]', N'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_database_files]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_database_files]
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_database_files]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_database_files
AS
SELECT [S].[server_instance_name], [S].[database_name], [S].[filegroup_name], [S].[Name] AS [Name],
[S].[volume_name], [S].[volume_device_id], [S].[FileName], [S].[Growth], [S].[GrowthType],
[S].[processing_time], [S].[powershell_path],
1 AS [file_type],
[S].[MaxSize], [S].[Size], [S].[UsedSpace], [S].[available_space], [S].[percent_utilization]
FROM [dbo].[sysutility_ucp_datafiles] AS S
UNION ALL
SELECT [S].[server_instance_name], [S].[database_name], N'' AS [filegroup_name], [S].[Name] AS [Name],
[S].[volume_name], [S].[volume_device_id], [S].[FileName], [S].[Growth], [S].[GrowthType],
[S].[processing_time], [S].[powershell_path],
2 AS [file_type],
[S].[MaxSize], [S].[Size], [S].[UsedSpace], [S].[available_space], [S].[percent_utilization]
FROM [dbo].[sysutility_ucp_logfiles] AS S
GO
/****************************************************************************/
/* */
/* Creating a utilization view on top of several object views in CMR which */
/* collects the data and log file related data for all databases in the */
/* utility */
/* */
/****************************************************************************/
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_mi_database_file_space_utilizations]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_mi_database_file_space_utilizations]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_mi_database_file_space_utilizations]
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_mi_database_file_space_utilizations]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW [dbo].[sysutility_ucp_mi_database_file_space_utilizations] AS
SELECT df.server_instance_name,
df.database_name,
df.filegroup_name,
df.Name,
df.volume_name,
df.volume_device_id,
df.FileName AS databasefile_name,
df.percent_utilization AS current_utilization,
df.UsedSpace AS used_space,
df.available_space AS available_space,
10 AS under_utilization,
70 AS over_utilization,
df.file_type,
df.GrowthType AS growth_type
FROM msdb.dbo.sysutility_ucp_database_files AS df
GO
/****************************************************************************/
/* */
/* Creating a utilization view on top of several object views in CMR which */
/* collects the data and log file related data for all deployed dacs in the */
/* utility */
/* */
/****************************************************************************/
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_dac_database_file_space_utilizations]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_dac_database_file_space_utilizations]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_dac_database_file_space_utilizations]
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_dac_database_file_space_utilizations]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW [dbo].[sysutility_ucp_dac_database_file_space_utilizations] AS
SELECT dd.dac_server_instance_name AS server_instance_name,
dd.dac_name AS dac_name,
df.[filegroup_name],
df.[Name],
df.volume_name,
df.volume_device_id,
df.FileName AS databasefile_name,
df.percent_utilization AS current_utilization,
df.UsedSpace AS used_space,
df.available_space,
10 AS under_utilization,
70 AS over_utilization,
df.file_type,
df.GrowthType AS growth_type
FROM msdb.dbo.sysutility_ucp_deployed_dacs AS dd,
msdb.dbo.sysutility_ucp_database_files AS df
WHERE dd.dac_server_instance_name = df.server_instance_name
AND dd.dac_name = df.database_name
GO
/****************************************************************************/
/* */
/* Creating a utilization view on top of several object views in CMR which */
/* collects the volume related data for all databases in the utility */
/* */
/****************************************************************************/
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_mi_volume_space_utilizations]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_mi_volume_space_utilizations]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_mi_volume_space_utilizations]
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_mi_volume_space_utilizations]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW [dbo].[sysutility_ucp_mi_volume_space_utilizations] AS(
-- TODO VSTS 280036(rnagpal) : Temporarily Keeping under_utilization to 10 and over_utilization to 70 for now
-- since we might reintroduce them in near future which will not require any interface change for the
-- Utility object model / UI. Presently, we are not exposing under and over utilization thresholds in UI
-- so they are not exposed. If that remains the same till KJ CTP2, i'll remove them.
SELECT vol.physical_server_name AS physical_server_name,
svr.Name as server_instance_name,
vol.volume_name AS volume_name,
vol.volume_device_id AS volume_device_id,
vol.total_space_utilization AS current_utilization,
vol.total_space_used AS used_space,
vol.total_space AS available_space,
10 AS under_utilization,
70 AS over_utilization
FROM msdb.dbo.sysutility_ucp_volumes AS vol,
msdb.dbo.sysutility_ucp_instances AS svr
WHERE vol.physical_server_name = svr.ComputerNamePhysicalNetBIOS)
GO
/****************************************************************************/
/* */
/* Creating a utilization view on top of several object views in CMR which */
/* collects the volume related data for all deployed dacs in the utility */
/* */
/****************************************************************************/
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_dac_volume_space_utilizations]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_dac_volume_space_utilizations]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_dac_volume_space_utilizations]
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_dac_volume_space_utilizations]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW [dbo].[sysutility_ucp_dac_volume_space_utilizations] AS(
-- TODO VSTS 280036(rnagpal) : Temporarily Keeping under_utilization to 10 and over_utilization to 70 for now
-- since we might reintroduce them in near future which will not require any interface change for the
-- Utility object model / UI. Presently, we are not exposing under and over utilization thresholds in UI
-- so they are not exposed. If that remains the same till KJ CTP2, i'll remove them.
SELECT vol.physical_server_name AS physical_server_name,
dd.dac_name AS dac_name,
dd.dac_server_instance_name AS server_instance_name,
vol.volume_name AS volume_name,
vol.volume_device_id AS volume_device_id,
vol.total_space_utilization AS current_utilization,
vol.total_space_used AS used_space,
vol.total_space AS available_space,
10 AS under_utilization,
70 AS over_utilization
FROM msdb.dbo.sysutility_ucp_volumes AS vol,
msdb.dbo.sysutility_ucp_deployed_dacs AS dd
WHERE vol.physical_server_name = dd.dac_physical_server_name)
GO
/****************************************************************************/
/* */
/* Creating a utilization view on top of several object views in CMR which */
/* collects the server related data for all instances in the utility */
/* */
/****************************************************************************/
-- TODO VSTS 280036(rnagpal) : Temporarily Keeping under_utilization to 10 and over_utilization to 70 for now
-- since we might reintroduce them in near future which will not require any interface change for the
-- Utility object model / UI. Presently, we are not exposing under and over utilization thresholds in UI
-- so they are not exposed. If that remains the same till KJ CTP2, i'll remove them.
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_mi_cpu_utilizations]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_mi_cpu_utilizations]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_mi_cpu_utilizations];
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_mi_cpu_utilizations]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW [dbo].[sysutility_ucp_mi_cpu_utilizations]
AS
SELECT svr.Name AS server_instance_name,
10 AS under_utilization,
CAST(svr.ProcessorUsage AS INT) AS current_utilization,
70 AS over_utilization
FROM msdb.dbo.sysutility_ucp_instances AS svr;
GO
/****************************************************************************/
/* */
/* Creating a utilization view on top of several object views in CMR which */
/* collects the computer related data for all computers in the utility */
/* */
/****************************************************************************/
-- TODO VSTS 280036(rnagpal) : Temporarily Keeping under_utilization to 10 and over_utilization to 70 for now
-- since we might reintroduce them in near future which will not require any interface change for the
-- Utility object model / UI. Presently, we are not exposing under and over utilization thresholds in UI
-- so they are not exposed. If that remains the same till KJ CTP2, i'll remove them.
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_computer_cpu_utilizations]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_computer_cpu_utilizations]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_computer_cpu_utilizations];
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_computer_cpu_utilizations]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW [dbo].[sysutility_ucp_computer_cpu_utilizations]
AS
SELECT comp.physical_server_name AS physical_server_name,
10 AS under_utilization,
comp.processor_utilization AS current_utilization,
70 AS over_utilization
FROM msdb.dbo.sysutility_ucp_computers AS comp
GO
/****************************************************************************/
/* */
/* Creating a utilization view on top of several object views in CMR which */
/* collects the DAC related data for all DACs in the utility */
/* */
/****************************************************************************/
-- TODO VSTS 280036(rnagpal) : Temporarily Keeping under_utilization to 10 and over_utilization to 70 for now
-- since we might reintroduce them in near future which will not require any interface change for the
-- Utility object model / UI. Presently, we are not exposing under and over utilization thresholds in UI
-- so they are not exposed. If that remains the same till KJ CTP2, i'll remove them.
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_dac_cpu_utilizations]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_dac_cpu_utilizations]', 0, 1) WITH NOWAIT;
DROP VIEW [dbo].[sysutility_ucp_dac_cpu_utilizations];
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_dac_cpu_utilizations]', 0, 1) WITH NOWAIT;
GO
CREATE VIEW [dbo].[sysutility_ucp_dac_cpu_utilizations]
AS
SELECT
dac.dac_name AS dac_name,
dac.dac_server_instance_name AS server_instance_name,
10 AS under_utilization,
dac.dac_percent_total_cpu_utilization AS current_utilization,
70 AS over_utilization
FROM msdb.dbo.sysutility_ucp_deployed_dacs AS dac
GO
/********************************************************************
Procedure sp_sysutility_ucp_provision_utility_object_internal
Helper proc that grants permissions (based on object type) to a role.
********************************************************************/
IF OBJECT_ID(N'dbo.sp_sysutility_ucp_provision_utility_object_internal') IS NOT NULL
BEGIN
RAISERROR('Dropping procedure dbo.sp_sysutility_ucp_provision_utility_object_internal', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_provision_utility_object_internal;
END
GO
RAISERROR('Creating procedure dbo.sp_sysutility_ucp_provision_utility_object_internal', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_provision_utility_object_internal
@object_name sysname, @role_name sysname
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE @sql_stmt nvarchar(max);
DECLARE @grant_type NVARCHAR(20);
DECLARE @object_type char(2);
DECLARE @database_name sysname;
DECLARE @quoted_object_name_with_dbo nvarchar(max);
SET @database_name = DB_NAME();
SET @quoted_object_name_with_dbo = 'dbo.' + QUOTENAME(@object_name);
SELECT @object_type = [type] FROM sys.objects WHERE object_id = OBJECT_ID(@quoted_object_name_with_dbo);
-- TSQL or CLR procs and non-inline functions
-- P - stored proc (TSQL)
-- PC - stored proc (SQLCLR)
-- FN - scalar function (TSQL)
-- FS - scalar function (SQLCLR)
IF (@object_type IN ('P', 'PC', 'FN', 'FS'))
BEGIN
SET @grant_type = 'EXECUTE';
END
-- Views, inline functions, tables
-- V - view
-- IF - inline function (TSQL)
-- U - user table
-- S - system table
-- TF - table-valued function (TSQL)
-- FT - table-valued function (SQLCLR)
ELSE IF (@object_type IN ('V', 'IF', 'U', 'S', 'FT', 'TF'))
BEGIN
SET @grant_type = 'SELECT';
END;
ELSE BEGIN
-- The object '%s' does not exist in database '%s' or is invalid for this operation.
RAISERROR (15009, 16, 1, @quoted_object_name_with_dbo, @database_name);
RETURN;
END;
SELECT @sql_stmt = N'GRANT '+ @grant_type +' ON ' + @quoted_object_name_with_dbo + ' TO ' + QUOTENAME(@role_name);
RAISERROR ('Executing: %s', 0, 1, @sql_stmt) WITH NOWAIT
EXEC sp_executesql @sql_stmt;
END;
GO
/**********************************************************************/
/* Create function fn_sysutility_ucp_get_aggregated_health
This function determines the aggregated health state based on the
input arguments over and under utilization policy violations.
The aggregated health state computation algorithm is as follows:
If both over and under utililization policy violations are 0 then its steady state (green)
If there is over utilization policy violation, then its over utilized state (red)
If there is under utilization policy violation (with no over utilization) then its under utilized state (orange)*/
/**********************************************************************/
IF(OBJECT_ID(N'dbo.fn_sysutility_ucp_get_aggregated_health') IS NOT NULL)
BEGIN
RAISERROR ('Dropping function fn_sysutility_ucp_get_aggregated_health', 0, 1) WITH NOWAIT;
DROP FUNCTION dbo.fn_sysutility_ucp_get_aggregated_health
END
GO
RAISERROR ('Creating function fn_sysutility_ucp_get_aggregated_health', 0, 1) WITH NOWAIT;
GO
CREATE FUNCTION [dbo].[fn_sysutility_ucp_get_aggregated_health]
(
@is_over_utilized INT,
@is_under_utilized INT
)
RETURNS TABLE
AS
RETURN ((SELECT
CASE WHEN 0 = @is_over_utilized AND 0 = @is_under_utilized THEN 1
ELSE CASE WHEN @is_over_utilized > 0 THEN 3
ELSE 2 END END AS val))
GO
--**********************************************************************
-- Create view sysutility_ucp_instance_policies
-- View Description:
-- Returns the resource health policy details for the managed instances
-- Powershell path - SQLSERVER:\SQL\<server_instance_name>
-- smo_server_urn - Server[@Name='<server_instance_name>']
-- utility_server_urn - Utility[@Name='<utility_name>']/Server[@Name='<server_instance_name>']
--Attribute description:
-- server_instance_name - the name of the server instance
-- smo_server_urn - the urn of the server in smo hiearchy (Server as the root)
-- utility_server_urn - the urn of the server in utility hiearchy (Utility as the root)
-- powershell_path - the path representing the server hiearchy in powershell
-- policy_id - resource health policy global / local (if exists)
-- resource_type - resource type on which the policy is configured
-- target_type - target type against which the policy is evaluated
-- utilization_type - type of the policy utilization (over/under) configuration
--*********************************************************************
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_instance_policies]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_instance_policies]', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_instance_policies
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_instance_policies]...', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_instance_policies AS
(
SELECT sp.server_instance_name
, sp.smo_server_urn
, sp.utility_server_urn
, sp.powershell_path
, ISNULL(lp.policy_id, sp.policy_id) AS policy_id -- if exists get local (overridden) policy, else return global policy
, ISNULL(lp.is_global_policy, 1) AS is_global_policy
, sp.resource_type
, sp.target_type
, sp.utilization_type
FROM (
-- fetch the global policies
SELECT sv.Name AS server_instance_name
, sv.urn AS smo_server_urn
, N'Utility[@Name=''' + CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName')) + N''']/' + sv.urn AS utility_server_urn
, sv.powershell_path AS powershell_path
, gp.policy_id
, gp.resource_type
, gp.target_type
, gp.utilization_type
FROM msdb.dbo.sysutility_ucp_instances sv
, msdb.dbo.sysutility_ucp_policies gp
WHERE gp.rollup_object_type = 2
AND gp.is_global_policy = 1
) sp
LEFT JOIN msdb.dbo.sysutility_ucp_policies lp -- fetch the local policies (if exists)
ON lp.rollup_object_urn = sp.utility_server_urn
AND lp.rollup_object_type = 2
AND lp.is_global_policy = 0
AND lp.resource_type = sp.resource_type
AND lp.target_type = sp.target_type
AND lp.utilization_type = sp.utilization_type
)
GO
--**********************************************************************
-- Create view sysutility_ucp_computer_policies
-- View Description:
-- Returns the resource health policy details for the computers
-- Powershell path - SQLSERVER:\Utility\<server_instance_name>\Computers\<computer_name>
-- computer_urn - Utility[@Name='<utility_name>']/Computer[@Name='<computer_name>']
--Attribute description:
-- physical_server_name - the name of the computer
-- computer_urn - the urn of the computer in utility hiearchy
-- powershell_path - the path representing the computer hiearchy in powershell
-- policy_id - resource health policy global / local (if exists)
-- resource_type - resource type on which the policy is configured
-- target_type - target type against which the policy is evaluated
-- utilization_type - type of the policy utilization (over/under) configuration
--*********************************************************************
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_computer_policies]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_computer_policies]', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_computer_policies
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_computer_policies]...', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_computer_policies AS
(
SELECT cp.physical_server_name
, cp.computer_urn
, cp.powershell_path
, ISNULL(lp.policy_id, cp.policy_id) AS policy_id -- if exists get local (overridden) policy, else return global policy
, ISNULL(lp.is_global_policy, 1) AS is_global_policy
, cp.resource_type
, cp.target_type
, cp.utilization_type
FROM
(
-- fetch the global policies
-- Should we be using "virtual_server_name" or "physical_server_name" here?
SELECT co.physical_server_name AS physical_server_name
, co.urn AS computer_urn
, co.powershell_path AS powershell_path
, gp.policy_id
, gp.resource_type
, gp.target_type
, gp.utilization_type
FROM msdb.dbo.sysutility_ucp_computers co
, msdb.dbo.sysutility_ucp_policies gp
WHERE gp.rollup_object_type = 3
AND gp.is_global_policy = 1
) cp
LEFT JOIN msdb.dbo.sysutility_ucp_policies lp -- fetch the local policies (if exists)
ON lp.rollup_object_urn = cp.computer_urn
AND lp.rollup_object_type = 3
AND lp.is_global_policy = 0
AND lp.resource_type = cp.resource_type
AND lp.target_type = cp.target_type
AND lp.utilization_type = cp.utilization_type
)
GO
--**********************************************************************
-- Create view sysutility_ucp_dac_policies
-- View Description:
-- Returns the resource health policy details for the dac's
-- Powershell path - SQLSERVER:\Utility\<server_instance_name>\DeployedDacs\<dac_name>.<dac_server_instance_name>
-- dac_urn - Utility[@Name='<utility_name>']/DeployedDac[@Name='<dac_name>' and @ServerInstanceName='<dac_server_instnace>']
--Attribute description:
-- dac_name - the name of the data-tier application
-- dac_server_instance_name - the server\instance on which the dac is hosted
-- dac_urn - the urn of the dac in utility hiearchy
-- powershell_path - the path representing the dac hiearchy in powershell
-- policy_id - resource health policy global / local (if exists)
-- resource_type - resource type on which the policy is configured
-- target_type - target type against which the policy is evaluated
-- utilization_type - type of the policy utilization (over/under) configuration
--*********************************************************************
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_dac_policies]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_dac_policies]', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_dac_policies
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_dac_policies]...', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_dac_policies AS
(
SELECT dp.dac_name
, dp.dac_server_instance_name
, dp.dac_urn
, dp.powershell_path
, ISNULL(lp.policy_id, dp.policy_id) AS policy_id -- if exists get local (overridden) policy, else return global policy
, ISNULL(lp.is_global_policy, 1) AS is_global_policy
, dp.resource_type
, dp.target_type
, dp.utilization_type
FROM
(
-- fetch the global policies
SELECT dd.dac_name
, dd.dac_server_instance_name
, dd.urn AS dac_urn
, dd.powershell_path AS powershell_path
, gp.policy_id
, gp.resource_type
, gp.target_type
, gp.utilization_type
FROM msdb.dbo.sysutility_ucp_deployed_dacs dd
, msdb.dbo.sysutility_ucp_policies gp
WHERE gp.rollup_object_type = 1
AND gp.is_global_policy = 1
) dp
LEFT JOIN msdb.dbo.sysutility_ucp_policies lp -- fetch the local policies (if exists)
ON lp.rollup_object_urn = dp.dac_urn
AND lp.rollup_object_type = 1
AND lp.is_global_policy = 0
AND lp.resource_type = dp.resource_type
AND lp.target_type = dp.target_type
AND lp.utilization_type = dp.utilization_type
)
GO
--**********************************************************************
-- Create view sysutility_ucp_dac_policy_type
-- This view selects the existing dac's and indicates whther the corresponding
-- resource health policy is global or overridden
--Attributes:
--1. dac_name - the name of the dac (rollup object)
--2. dac_server_instance_name - the name of the smo server in the form server_name\instance_name
--3. is_global_policy - Indicates whether the policy type is global or overridden
--*********************************************************************
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_dac_policy_type]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_dac_policy_type]', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_dac_policy_type
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_dac_policy_type]...', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_dac_policy_type AS
(
-- Target types
-- computer_type = 1
-- volume_type = 6
-- Resource types
-- processor_type = 3
-- space_type = 1
SELECT DISTINCT dd.dac_server_instance_name
, dd.dac_name
, CASE WHEN ((0 < ip.is_policy_overridden) OR (0 < cp.is_policy_overridden)) THEN 1 ELSE 0 END AS is_policy_overridden
FROM msdb.dbo.sysutility_ucp_deployed_dacs dd
, (SELECT dac_name, dac_server_instance_name, SUM(CASE WHEN 0 < is_global_policy THEN 0 ELSE 1 END) AS is_policy_overridden
FROM msdb.dbo.sysutility_ucp_dac_policies
GROUP BY dac_name, dac_server_instance_name) ip
, (SELECT physical_server_name, SUM(CASE WHEN 0 < is_global_policy THEN 0 ELSE 1 END) AS is_policy_overridden
FROM msdb.dbo.sysutility_ucp_computer_policies
GROUP BY physical_server_name) cp
WHERE ip.dac_name = dd.dac_name
AND ip.dac_server_instance_name = dd.dac_server_instance_name
AND cp.physical_server_name = dd.dac_physical_server_name
)
GO
--**********************************************************************
-- Create view sysutility_ucp_instance_policy_type
-- This view selects the existing server's and indicates whther the corresponding
-- resource health policy is global or overridden
--Attributes:
--1. server_instance_name - the name of the smo server in the form server_name\instance_name
--2. is_global_policy - Indicates whether the policy type is global or overridden
--*********************************************************************
IF (OBJECT_ID(N'[dbo].[sysutility_ucp_instance_policy_type]', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view [dbo].[sysutility_ucp_instance_policy_type]', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_instance_policy_type
END
GO
RAISERROR ('Creating view [dbo].[sysutility_ucp_instance_policy_type]...', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_instance_policy_type AS
(
-- Target types
-- computer_type = 1
-- volume_type = 6
-- Resource types
-- processor_type = 3
-- space_type = 1
SELECT sv.Name AS server_instance_name
, CASE WHEN ((0 < ip.is_policy_overridden) OR (0 < cp.is_policy_overridden)) THEN 1 ELSE 0 END AS is_policy_overridden
FROM msdb.dbo.sysutility_ucp_instances sv
, (SELECT server_instance_name , SUM(CASE WHEN 0 < is_global_policy THEN 0 ELSE 1 END) AS is_policy_overridden
FROM msdb.dbo.sysutility_ucp_instance_policies
GROUP BY server_instance_name) ip
, (SELECT physical_server_name, SUM(CASE WHEN 0 < is_global_policy THEN 0 ELSE 1 END) AS is_policy_overridden
FROM msdb.dbo.sysutility_ucp_computer_policies
GROUP BY physical_server_name) cp
WHERE ip.server_instance_name = sv.Name
AND cp.physical_server_name = sv.ComputerNamePhysicalNetBIOS
)
GO
/**********************************************************************/
/* Create table sysutility_ucp_mi_file_space_health_internal */
/* This table stores the file-space health states for data/log file groups of MI */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_mi_file_space_health_internal', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table dbo.sysutility_ucp_mi_file_space_health_internal', 0, 1) WITH NOWAIT;
CREATE TABLE dbo.sysutility_ucp_mi_file_space_health_internal
(
server_instance_name SYSNAME NOT NULL
, database_name SYSNAME NOT NULL
, fg_name SYSNAME NOT NULL
, over_utilized_count INT NOT NULL DEFAULT(0)
, under_utilized_count INT NOT NULL DEFAULT(0)
, file_type INT NOT NULL
, set_number INT NOT NULL DEFAULT(0)
, processing_time DATETIMEOFFSET(7) NOT NULL DEFAULT(SYSDATETIMEOFFSET())
CONSTRAINT [PK_sysutility_ucp_mi_file_space_health_internal_name]
PRIMARY KEY CLUSTERED (set_number, server_instance_name, database_name, fg_name)
)
END
GO
/**********************************************************************/
/* Create table sysutility_ucp_mi_database_health_internal */
/* This table stores the file-space health states for databases of MI */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_mi_database_health_internal', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table dbo.sysutility_ucp_mi_database_health_internal', 0, 1) WITH NOWAIT;
CREATE TABLE dbo.sysutility_ucp_mi_database_health_internal
(
server_instance_name SYSNAME NOT NULL
, database_name SYSNAME NOT NULL
, over_utilized_count INT NOT NULL DEFAULT(0)
, under_utilized_count INT NOT NULL DEFAULT(0)
, set_number INT NOT NULL DEFAULT(0)
, processing_time DATETIMEOFFSET(7) NOT NULL DEFAULT(SYSDATETIMEOFFSET())
CONSTRAINT [PK_sysutility_ucp_mi_database_health_internal_name]
PRIMARY KEY CLUSTERED (set_number, server_instance_name, database_name)
)
END
GO
/**********************************************************************/
/* Create table sysutility_ucp_dac_file_space_health_internal */
/* This table stores the file-space health states for data/log file groups of DAC */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_dac_file_space_health_internal', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table dbo.sysutility_ucp_dac_file_space_health_internal', 0, 1) WITH NOWAIT;
CREATE TABLE dbo.sysutility_ucp_dac_file_space_health_internal
(
dac_name SYSNAME NOT NULL
, dac_server_instance_name SYSNAME NOT NULL
, fg_name SYSNAME NOT NULL
, over_utilized_count INT NOT NULL DEFAULT(0)
, under_utilized_count INT NOT NULL DEFAULT(0)
, file_type INT NOT NULL
, set_number INT NOT NULL DEFAULT(0)
, processing_time DATETIMEOFFSET(7) NOT NULL DEFAULT(SYSDATETIMEOFFSET())
CONSTRAINT [PK_sysutility_ucp_dac_file_space_health_internal_name]
PRIMARY KEY CLUSTERED (set_number, dac_server_instance_name, dac_name, fg_name)
)
END
GO
/**********************************************************************/
/* Create table sysutility_ucp_mi_volume_space_health_internal */
/* This table stores the volume-space health states for computer MI's */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_mi_volume_space_health_internal', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table dbo.sysutility_ucp_mi_volume_space_health_internal', 0, 1) WITH NOWAIT;
CREATE TABLE dbo.sysutility_ucp_mi_volume_space_health_internal
(
physical_server_name SYSNAME NOT NULL
, server_instance_name SYSNAME NOT NULL
, volume_device_id SYSNAME NOT NULL
, health_state INT NOT NULL
, set_number INT NOT NULL DEFAULT(0)
, processing_time DATETIMEOFFSET(7) NOT NULL DEFAULT(SYSDATETIMEOFFSET())
CONSTRAINT [PK_sysutility_ucp_mi_volume_space_health_internal_name]
PRIMARY KEY CLUSTERED (set_number, server_instance_name, volume_device_id)
)
END
GO
/**********************************************************************/
/* Create table sysutility_ucp_computer_cpu_health_internal */
/* This table stores the processor health states for computer */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_computer_cpu_health_internal', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table dbo.sysutility_ucp_computer_cpu_health_internal', 0, 1) WITH NOWAIT;
CREATE TABLE dbo.sysutility_ucp_computer_cpu_health_internal
(
physical_server_name SYSNAME NOT NULL
, health_state INT NOT NULL
, set_number INT NOT NULL DEFAULT(0)
, processing_time DATETIMEOFFSET(7) NOT NULL DEFAULT(SYSDATETIMEOFFSET())
CONSTRAINT [PK_sysutility_ucp_computer_cpu_health_internal_name]
PRIMARY KEY CLUSTERED (set_number, physical_server_name)
)
END
GO
/**********************************************************************/
/* Create view sysutility_ucp_computer_cpu_health */
/* This view returns the latest processor health states for computers */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_computer_cpu_health', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view dbo.sysutility_ucp_computer_cpu_health', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_computer_cpu_health
END
GO
CREATE VIEW dbo.sysutility_ucp_computer_cpu_health
AS
SELECT t.physical_server_name,
t.health_state,
t.processing_time
FROM msdb.dbo.sysutility_ucp_computer_cpu_health_internal AS t
WHERE t.set_number = (SELECT latest_health_state_id FROM [msdb].[dbo].[sysutility_ucp_processing_state_internal])
GO
/**********************************************************************/
/* Create view sysutility_ucp_mi_volume_space_health */
/* This view returns the latest volume space health states for computers */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_mi_volume_space_health', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view dbo.sysutility_ucp_mi_volume_space_health', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_mi_volume_space_health
END
GO
CREATE VIEW dbo.sysutility_ucp_mi_volume_space_health
AS
SELECT t.physical_server_name,
t.server_instance_name,
t.volume_device_id,
t.health_state,
t.processing_time
FROM msdb.dbo.sysutility_ucp_mi_volume_space_health_internal AS t
WHERE t.set_number = (SELECT latest_health_state_id FROM [msdb].[dbo].[sysutility_ucp_processing_state_internal])
GO
/**********************************************************************/
/* Create view sysutility_ucp_mi_file_space_health */
/* This view returns the latest file space health states for MI's */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_mi_file_space_health', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view dbo.sysutility_ucp_mi_file_space_health', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_mi_file_space_health
END
GO
CREATE VIEW dbo.sysutility_ucp_mi_file_space_health
AS
SELECT t.server_instance_name,
t.database_name,
t.fg_name,
t.file_type,
(SELECT val FROM dbo.fn_sysutility_ucp_get_aggregated_health(t.over_utilized_count, t.under_utilized_count)) health_state,
t.processing_time
FROM msdb.dbo.sysutility_ucp_mi_file_space_health_internal AS t
WHERE t.set_number = (SELECT latest_health_state_id FROM [msdb].[dbo].[sysutility_ucp_processing_state_internal])
GO
/**********************************************************************/
/* Create view sysutility_ucp_mi_database_health */
/* This view returns the latest database health states for MI's */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_mi_database_health', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view dbo.sysutility_ucp_mi_database_health', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_mi_database_health
END
GO
CREATE VIEW dbo.sysutility_ucp_mi_database_health
AS
SELECT t.server_instance_name,
t.database_name,
(SELECT val FROM dbo.fn_sysutility_ucp_get_aggregated_health(t.over_utilized_count, t.under_utilized_count)) health_state,
t.processing_time
FROM msdb.dbo.sysutility_ucp_mi_database_health_internal AS t
WHERE t.set_number = (SELECT latest_health_state_id FROM [msdb].[dbo].[sysutility_ucp_processing_state_internal])
GO
/**********************************************************************/
/* Create view sysutility_ucp_dac_database_file_space_health */
/* This view returns the latest filespace health states for DAC's */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_dac_database_file_space_health', 'V') IS NOT NULL)
BEGIN
RAISERROR ('Dropping view dbo.sysutility_ucp_dac_database_file_space_health', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_dac_database_file_space_health
END
GO
CREATE VIEW dbo.sysutility_ucp_dac_database_file_space_health
AS
SELECT t.dac_name
, t.dac_server_instance_name
, t.fg_name
, t.file_type
, (SELECT val FROM dbo.fn_sysutility_ucp_get_aggregated_health(t.over_utilized_count, t.under_utilized_count)) health_state
, t.processing_time
FROM msdb.dbo.sysutility_ucp_dac_file_space_health_internal AS t
WHERE t.set_number = (SELECT latest_health_state_id FROM [msdb].[dbo].[sysutility_ucp_processing_state_internal])
GO
/**********************************************************************/
/* Create table sysutility_ucp_aggregated_dac_health_internal */
/* This table stores the aggregated health statistics for DAC's */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_aggregated_dac_health_internal', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table dbo.sysutility_ucp_aggregated_dac_health_internal', 0, 1) WITH NOWAIT;
CREATE TABLE dbo.sysutility_ucp_aggregated_dac_health_internal
(
dac_count INT NOT NULL DEFAULT(0)
, dac_healthy_count INT NOT NULL DEFAULT(0)
, dac_unhealthy_count INT NOT NULL DEFAULT(0)
, dac_over_utilize_count INT NOT NULL DEFAULT(0)
, dac_under_utilize_count INT NOT NULL DEFAULT(0)
, dac_on_over_utilized_computer_count INT NOT NULL DEFAULT(0)
, dac_on_under_utilized_computer_count INT NOT NULL DEFAULT(0)
, dac_with_files_on_over_utilized_volume_count INT NOT NULL DEFAULT(0)
, dac_with_files_on_under_utilized_volume_count INT NOT NULL DEFAULT(0)
, dac_with_over_utilized_file_count INT NOT NULL DEFAULT(0)
, dac_with_under_utilized_file_count INT NOT NULL DEFAULT(0)
, dac_with_over_utilized_processor_count INT NOT NULL DEFAULT(0)
, dac_with_under_utilized_processor_count INT NOT NULL DEFAULT(0)
, set_number INT NOT NULL DEFAULT(0)
)
END
GO
/**********************************************************************/
/* Create table sysutility_ucp_aggregated_mi_health_internal */
/* This table stores the aggregated health statistics for MI's */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_aggregated_mi_health_internal', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table dbo.sysutility_ucp_aggregated_mi_health_internal', 0, 1) WITH NOWAIT;
CREATE TABLE sysutility_ucp_aggregated_mi_health_internal
(
mi_count INT NOT NULL DEFAULT(0)
, mi_healthy_count INT NOT NULL DEFAULT(0)
, mi_unhealthy_count INT NOT NULL DEFAULT(0)
, mi_over_utilize_count INT NOT NULL DEFAULT(0)
, mi_under_utilize_count INT NOT NULL DEFAULT(0)
, mi_on_over_utilized_computer_count INT NOT NULL DEFAULT(0)
, mi_on_under_utilized_computer_count INT NOT NULL DEFAULT(0)
, mi_with_files_on_over_utilized_volume_count INT NOT NULL DEFAULT(0)
, mi_with_files_on_under_utilized_volume_count INT NOT NULL DEFAULT(0)
, mi_with_over_utilized_file_count INT NOT NULL DEFAULT(0)
, mi_with_under_utilized_file_count INT NOT NULL DEFAULT(0)
, mi_with_over_utilized_processor_count INT NOT NULL DEFAULT(0)
, mi_with_under_utilized_processor_count INT NOT NULL DEFAULT(0)
, set_number INT NOT NULL DEFAULT(0)
)
END
GO
/**********************************************************************/
/* Create table sysutility_ucp_dac_health_internal */
/* This table stores the resource health states for DAC's */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_dac_health_internal', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table dbo.sysutility_ucp_dac_health_internal', 0, 1) WITH NOWAIT;
CREATE TABLE sysutility_ucp_dac_health_internal
(
dac_name SYSNAME NOT NULL
, dac_server_instance_name SYSNAME NOT NULL
, is_volume_space_over_utilized INT NOT NULL DEFAULT(0)
, is_volume_space_under_utilized INT NOT NULL DEFAULT(0)
, is_computer_processor_over_utilized INT NOT NULL DEFAULT(0)
, is_computer_processor_under_utilized INT NOT NULL DEFAULT(0)
, is_file_space_over_utilized INT NOT NULL DEFAULT(0)
, is_file_space_under_utilized INT NOT NULL DEFAULT(0)
, is_dac_processor_over_utilized INT NOT NULL DEFAULT(0)
, is_dac_processor_under_utilized INT NOT NULL DEFAULT(0)
, is_policy_overridden BIT NOT NULL DEFAULT(0)
, set_number INT NOT NULL DEFAULT(0)
, processing_time DATETIMEOFFSET(7) NOT NULL DEFAULT(SYSDATETIMEOFFSET())
CONSTRAINT [PK_sysutility_ucp_dac_health_internal_name]
PRIMARY KEY CLUSTERED (set_number, dac_server_instance_name, dac_name)
)
END
GO
/**********************************************************************/
/* Create table sysutility_ucp_mi_health_internal */
/* This table stores the resource health states for MI's */
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_mi_health_internal', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table dbo.sysutility_ucp_mi_health_internal', 0, 1) WITH NOWAIT;
CREATE TABLE sysutility_ucp_mi_health_internal
(
mi_name SYSNAME NOT NULL
, is_volume_space_over_utilized INT NOT NULL DEFAULT(0)
, is_volume_space_under_utilized INT NOT NULL DEFAULT(0)
, is_computer_processor_over_utilized INT NOT NULL DEFAULT(0)
, is_computer_processor_under_utilized INT NOT NULL DEFAULT(0)
, is_file_space_over_utilized INT NOT NULL DEFAULT(0)
, is_file_space_under_utilized INT NOT NULL DEFAULT(0)
, is_mi_processor_over_utilized INT NOT NULL DEFAULT(0)
, is_mi_processor_under_utilized INT NOT NULL DEFAULT(0)
, is_policy_overridden BIT NOT NULL DEFAULT(0)
, set_number INT NOT NULL DEFAULT(0)
, processing_time DATETIMEOFFSET(7) NOT NULL DEFAULT(SYSDATETIMEOFFSET())
CONSTRAINT [PK_sysutility_ucp_mi_health_internal_name]
PRIMARY KEY CLUSTERED (set_number, mi_name)
)
END
GO
/**********************************************************************/
/* Create the sysutility_ucp_aggregated_dac_health */
/* This view returns the latest health statistics for DAC's */
/**********************************************************************/
IF object_id(N'dbo.sysutility_ucp_aggregated_dac_health', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view dbo.sysutility_ucp_mi_health_internal', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_aggregated_dac_health
END;
GO
RAISERROR ('Creating view dbo.sysutility_ucp_aggregated_dac_health', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_aggregated_dac_health
AS
SELECT t.dac_count
, t.dac_healthy_count
, t.dac_unhealthy_count
, t.dac_over_utilize_count
, t.dac_under_utilize_count
, t.dac_on_over_utilized_computer_count
, t.dac_on_under_utilized_computer_count
, t.dac_with_files_on_over_utilized_volume_count
, t.dac_with_files_on_under_utilized_volume_count
, t.dac_with_over_utilized_file_count
, t.dac_with_under_utilized_file_count
, t.dac_with_over_utilized_processor_count
, t.dac_with_under_utilized_processor_count
FROM msdb.dbo.sysutility_ucp_aggregated_dac_health_internal AS t
WHERE t.set_number = (SELECT latest_health_state_id FROM [msdb].[dbo].[sysutility_ucp_processing_state_internal])
GO
/**********************************************************************/
/* Create the sysutility_ucp_aggregated_mi_health */
/* This view returns the latest health statistics for MI's */
/**********************************************************************/
IF object_id(N'dbo.sysutility_ucp_aggregated_mi_health', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view dbo.sysutility_ucp_aggregated_mi_health', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_aggregated_mi_health
END;
GO
RAISERROR ('Creating view dbo.sysutility_ucp_aggregated_mi_health', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_aggregated_mi_health
AS
SELECT t.mi_count
, t.mi_healthy_count
, t.mi_unhealthy_count
, t.mi_over_utilize_count
, t.mi_under_utilize_count
, t.mi_on_over_utilized_computer_count
, t.mi_on_under_utilized_computer_count
, t.mi_with_files_on_over_utilized_volume_count
, t.mi_with_files_on_under_utilized_volume_count
, t.mi_with_over_utilized_file_count
, t.mi_with_under_utilized_file_count
, t.mi_with_over_utilized_processor_count
, t.mi_with_under_utilized_processor_count
FROM msdb.dbo.sysutility_ucp_aggregated_mi_health_internal AS t
WHERE t.set_number = (SELECT latest_health_state_id FROM [msdb].[dbo].[sysutility_ucp_processing_state_internal])
GO
/**********************************************************************/
/* Create the sysutility_ucp_dac_health */
/* This view returns the latest resource health states for DAC's */
/**********************************************************************/
IF object_id(N'dbo.sysutility_ucp_dac_health', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view dbo.sysutility_ucp_dac_health', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_dac_health
END;
GO
RAISERROR ('Creating view dbo.sysutility_ucp_dac_health', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_dac_health
AS
SELECT t.dac_name
, t.dac_server_instance_name
, (SELECT val FROM dbo.fn_sysutility_ucp_get_aggregated_health(t.is_volume_space_over_utilized, t.is_volume_space_under_utilized)) volume_space_health_state
, (SELECT val FROM dbo.fn_sysutility_ucp_get_aggregated_health(t.is_computer_processor_over_utilized, t.is_computer_processor_under_utilized)) computer_processor_health_state
, (SELECT val FROM dbo.fn_sysutility_ucp_get_aggregated_health(t.is_file_space_over_utilized, t.is_file_space_under_utilized)) file_space_health_state
, (SELECT val FROM dbo.fn_sysutility_ucp_get_aggregated_health(t.is_dac_processor_over_utilized, t.is_dac_processor_under_utilized)) dac_processor_health_state
, CASE WHEN (is_volume_space_over_utilized > 0) THEN CONVERT(BIT, 1) ELSE CONVERT(BIT, 0) END AS contains_over_utilized_volumes
, CASE WHEN (is_volume_space_under_utilized > 0) THEN CONVERT(BIT, 1) ELSE CONVERT(BIT, 0) END AS contains_under_utilized_volumes
, CASE WHEN (is_file_space_over_utilized > 0) THEN CONVERT(BIT, 1) ELSE CONVERT(BIT, 0) END AS contains_over_utilized_filegroups
, CASE WHEN (is_file_space_under_utilized > 0) THEN CONVERT(BIT, 1) ELSE CONVERT(BIT, 0) END AS contains_under_utilized_filegroups
, t.is_policy_overridden
, t.processing_time
FROM msdb.dbo.sysutility_ucp_dac_health_internal AS t
WHERE t.set_number = (SELECT latest_health_state_id FROM [msdb].[dbo].[sysutility_ucp_processing_state_internal])
GO
/**********************************************************************/
/* Create the sysutility_ucp_mi_health */
/* This view returns the latest resource health states for MI's */
/**********************************************************************/
IF object_id(N'dbo.sysutility_ucp_mi_health', 'V') IS NOT NULL
BEGIN
RAISERROR ('Dropping view dbo.sysutility_ucp_mi_health', 0, 1) WITH NOWAIT;
DROP VIEW dbo.sysutility_ucp_mi_health
END;
GO
RAISERROR ('Creating view dbo.sysutility_ucp_mi_health', 0, 1) WITH NOWAIT;
GO
CREATE VIEW dbo.sysutility_ucp_mi_health
AS
SELECT t.mi_name
, (SELECT val FROM dbo.fn_sysutility_ucp_get_aggregated_health(t.is_volume_space_over_utilized, t.is_volume_space_under_utilized)) volume_space_health_state
, (SELECT val FROM dbo.fn_sysutility_ucp_get_aggregated_health(t.is_computer_processor_over_utilized, t.is_computer_processor_under_utilized)) computer_processor_health_state
, (SELECT val FROM dbo.fn_sysutility_ucp_get_aggregated_health(t.is_file_space_over_utilized, t.is_file_space_under_utilized)) file_space_health_state
, (SELECT val FROM dbo.fn_sysutility_ucp_get_aggregated_health(t.is_mi_processor_over_utilized, t.is_mi_processor_under_utilized)) mi_processor_health_state
, CASE WHEN (is_volume_space_over_utilized > 0) THEN CONVERT(BIT, 1) ELSE CONVERT(BIT, 0) END AS contains_over_utilized_volumes
, CASE WHEN (is_volume_space_under_utilized > 0) THEN CONVERT(BIT, 1) ELSE CONVERT(BIT, 0) END AS contains_under_utilized_volumes
, CASE WHEN (is_file_space_over_utilized > 0) THEN CONVERT(BIT, 1) ELSE CONVERT(BIT, 0) END AS contains_over_utilized_databases
, CASE WHEN (is_file_space_under_utilized > 0) THEN CONVERT(BIT, 1) ELSE CONVERT(BIT, 0) END AS contains_under_utilized_databases
, t.is_policy_overridden
, t.processing_time
FROM msdb.dbo.sysutility_ucp_mi_health_internal AS t
WHERE t.set_number = (SELECT latest_health_state_id FROM [msdb].[dbo].[sysutility_ucp_processing_state_internal])
GO
/**********************************************************************/
-- Table sysutility_ucp_filegroups_with_policy_violations_internal */
-- This table stores an entry for each filegroup that has at least one file
-- that violates the specified policy.
-- LogFiles are rolled up into an entry (with filegroup_name = N'')
/**********************************************************************/
IF(OBJECT_ID(N'dbo.sysutility_ucp_filegroups_with_policy_violations_internal', 'U') IS NULL)
BEGIN
RAISERROR ('Creating table dbo.sysutility_ucp_filegroups_with_policy_violations_internal', 0, 1) WITH NOWAIT;
CREATE TABLE sysutility_ucp_filegroups_with_policy_violations_internal
(
server_instance_name SYSNAME,
database_name SYSNAME,
[filegroup_name] SYSNAME, -- N'' for log files
policy_id INT, -- id of the offending policy
set_number INT NOT NULL,
CONSTRAINT [PK_sysutility_ucp_filegroups_with_policy_violations_internal]
PRIMARY KEY CLUSTERED (set_number, policy_id, server_instance_name, database_name, [filegroup_name])
)
END
GO
--*********************************************************************
-- Procedure sp_sysutility_ucp_calculate_filegroups_with_policy_violations
-- Description: This function identifies filegroups where *every* single file
-- violates a policy (the same policy for all files in the filegroups).
-- Logfiles are also captured here under a special entry (with filegroup_name = N'')
--**********************************************************************
IF OBJECT_ID ('dbo.sp_sysutility_ucp_calculate_filegroups_with_policy_violations') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_calculate_filegroups_with_policy_violations', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_calculate_filegroups_with_policy_violations
END;
GO
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_calculate_filegroups_with_policy_violations', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_calculate_filegroups_with_policy_violations
@new_set_number INT
WITH EXECUTE AS OWNER
AS
BEGIN
INSERT INTO sysutility_ucp_filegroups_with_policy_violations_internal(
server_instance_name,
database_name,
[filegroup_name],
policy_id,
set_number)
SELECT fg1.server_instance_name,
fg1.database_name,
fg1.[filegroup_name],
fg1.policy_id,
@new_set_number
FROM (SELECT pv.policy_id,
f.server_instance_name, f.database_name, f.[filegroup_name],
COUNT(*) as policy_violations
FROM dbo.sysutility_ucp_database_files AS f,
dbo.sysutility_ucp_policy_violations AS pv
WHERE f.powershell_path = pv.target_query_expression
GROUP BY pv.policy_id, f.server_instance_name, f.database_name, f.[filegroup_name]) as fg1,
(SELECT f.server_instance_name, f.database_name, f.[filegroup_name],
COUNT(*) as file_count
FROM dbo.sysutility_ucp_database_files AS f
GROUP BY f.server_instance_name, f.database_name, f.[filegroup_name]) AS fg2
WHERE fg1.server_instance_name = fg2.server_instance_name AND
fg1.database_name = fg2.database_name AND
fg1.[filegroup_name] = fg2.[filegroup_name] AND
fg1.policy_violations = fg2.file_count
END
GO
--*********************************************************************
--*********************************************************************
-- Create procedure sp_sysutility_ucp_calculate_dac_file_space_health
-- Description: Computes the file space (data/log file group)health state for the DAC's
-- The computed result is consumed by the UI for health state drill down and further
-- compute the rollup health state for the DAC's
--**********************************************************************
IF(OBJECT_ID(N'dbo.sp_sysutility_ucp_calculate_dac_file_space_health', 'P') IS NOT NULL)
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_calculate_dac_file_space_health', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_calculate_dac_file_space_health
END
GO
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_calculate_dac_file_space_health', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_calculate_dac_file_space_health
@new_set_number INT
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @under_utilize_type INT = 1
DECLARE @over_utilize_type INT = 2;
-- space_resource_type = 1
-- datafile_target_type = 2
-- logfile_target_type = 3
INSERT INTO msdb.dbo.sysutility_ucp_dac_file_space_health_internal(
dac_name, dac_server_instance_name,
fg_name, set_number, processing_time
, over_utilized_count
, under_utilized_count
, file_type)
-- Insert the dac filegroup utilization details
SELECT dd.dac_name
, dd.dac_server_instance_name
, fg.Name AS file_group_name
, @new_set_number
, dd.dac_processing_time
, SUM(CASE WHEN df.policy_id IS NOT NULL AND dp.utilization_type = 2 THEN 1 ELSE 0 END) AS over_utilized_count
, SUM(CASE WHEN df.policy_id IS NOT NULL AND dp.utilization_type = 1 THEN 1 ELSE 0 END) AS under_utilized_count
, fg.file_type
FROM msdb.dbo.sysutility_ucp_deployed_dacs AS dd
INNER JOIN (SELECT 1 AS file_type, server_instance_name, database_name, [Name], processing_time
FROM msdb.dbo.sysutility_ucp_filegroups
UNION ALL
SELECT 2 AS file_type, server_instance_name, Name as database_name, N'' AS [Name], processing_time
FROM msdb.dbo.sysutility_ucp_databases) AS fg
ON dd.dac_server_instance_name = fg.server_instance_name AND
dd.dac_name = fg.database_name
INNER JOIN msdb.dbo.sysutility_ucp_dac_policies AS dp
ON dp.dac_name = dd.dac_name AND
dp.dac_server_instance_name = dd.dac_server_instance_name
LEFT JOIN msdb.dbo.sysutility_ucp_filegroups_with_policy_violations_internal AS df
ON df.server_instance_name = dd.dac_server_instance_name AND
df.database_name = dd.dac_name AND
fg.Name = df.filegroup_name AND
dp.policy_id = df.policy_id AND
df.set_number = @new_set_number
WHERE dp.resource_type = 1
AND dp.target_type = fg.file_type + 1 -- target_type = 2 (datafile); 3 (logfile)
GROUP BY dd.dac_name, dd.dac_server_instance_name, fg.Name , fg.file_type, dd.dac_processing_time
END
GO
--*********************************************************************
-- Create procedure sp_sysutility_ucp_calculate_mi_file_space_health
-- Description: Computes the file space (data/log file group)health state for the MI's
-- The computed result is consumed by the UI for health state drill down and further
-- compute the rollup health state for the MI's
--**********************************************************************
IF(OBJECT_ID(N'dbo.sp_sysutility_ucp_calculate_mi_file_space_health', 'P') IS NOT NULL)
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_calculate_mi_file_space_health', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_calculate_mi_file_space_health
END
GO
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_calculate_mi_file_space_health', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_calculate_mi_file_space_health
@new_set_number INT
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @under_utilize_type INT = 1
DECLARE @over_utilize_type INT = 2;
-- space_resource_type = 1
-- datafile_target_type = 2
-- logfile_target_type = 3
INSERT INTO msdb.dbo.sysutility_ucp_mi_file_space_health_internal(
server_instance_name
, database_name
, fg_name
, set_number
, processing_time
, over_utilized_count
, under_utilized_count
, file_type)
-- Insert the server filegroup utilization details
SELECT fg.server_instance_name
, fg.database_name
, fg.Name AS file_group_name
, @new_set_number
, fg.processing_time
, SUM(CASE WHEN df.policy_id IS NOT NULL AND ip.utilization_type = 2 THEN 1 ELSE 0 END) AS over_utilized_count
, SUM(CASE WHEN df.policy_id IS NOT NULL AND ip.utilization_type = 1 THEN 1 ELSE 0 END) AS under_utilized_count
, fg.file_type
FROM (SELECT 1 AS file_type, fg.server_instance_name, fg.database_name, fg.Name, fg.processing_time
FROM msdb.dbo.sysutility_ucp_filegroups AS fg
UNION ALL
SELECT 2 AS file_type, db.server_instance_name, db.Name AS database_name, N'' AS Name, db.processing_time
FROM msdb.dbo.sysutility_ucp_databases AS db) AS fg
INNER JOIN msdb.dbo.sysutility_ucp_instance_policies AS ip ON fg.server_instance_name = ip.server_instance_name
LEFT JOIN msdb.dbo.sysutility_ucp_filegroups_with_policy_violations_internal AS df
ON fg.server_instance_name = df.server_instance_name AND
fg.database_name = df.database_name AND
fg.Name = df.[filegroup_name] AND
df.set_number = @new_set_number AND
ip.policy_id = df.policy_id
WHERE ip.resource_type = 1
AND ip.target_type = file_type + 1 -- target_type = 2 (datafile), 3 (logfile)
GROUP BY fg.server_instance_name, fg.database_name, fg.Name, fg.file_type, fg.processing_time
-- Compute the database health state for the MI's based on the file-space computation.
-- Insert the server database utilization details
INSERT INTO msdb.dbo.sysutility_ucp_mi_database_health_internal(server_instance_name, database_name, set_number, processing_time
, over_utilized_count
, under_utilized_count)
SELECT fs.server_instance_name
, fs.database_name AS database_name
, @new_set_number
, svr.processing_time
, SUM(fs.over_utilized_count) AS over_utilized_count
, SUM(fs.under_utilized_count) AS under_utilized_count
FROM msdb.dbo.sysutility_ucp_mi_file_space_health_internal AS fs
, msdb.dbo.sysutility_ucp_instances AS svr
WHERE svr.Name = fs.server_instance_name AND
fs.set_number = @new_set_number
GROUP BY fs.server_instance_name, fs.database_name, svr.processing_time
END
GO
--*********************************************************************
-- Create procedure sp_sysutility_ucp_calculate_computer_health
-- Description: Computes the volume space health state for the computer.
-- The computed result is consumed by the DAC / MI to determine rollup health state
--**********************************************************************
IF(OBJECT_ID(N'dbo.sp_sysutility_ucp_calculate_computer_health', 'P') IS NOT NULL)
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_calculate_computer_health', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_calculate_computer_health
END
GO
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_calculate_computer_health', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_calculate_computer_health
@new_set_number INT
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @under_utilize_type INT = 1
DECLARE @over_utilize_type INT = 2
DECLARE @computer_object_type INT = 3
DECLARE @target_type INT = 6
DECLARE @space_resource_type INT = 1;
-- Compute the volume space health state for the computer.
-- CTE to identify the computer volumes violating the under / over utilization policy
WITH volume_utilization (physical_server_name, volume_device_id, utilization_type)
AS
(
SELECT vo.physical_server_name, vo.volume_device_id, cp.utilization_type
FROM msdb.dbo.sysutility_ucp_computer_policies cp
, msdb.dbo.sysutility_ucp_volumes vo
, msdb.dbo.sysutility_ucp_policy_violations pv
WHERE cp.physical_server_name = vo.physical_server_name
AND cp.resource_type = @space_resource_type
AND cp.target_type = @target_type
AND pv.policy_id = cp.policy_id
AND pv.target_query_expression = vo.powershell_path
)
-- Insert new record
INSERT INTO msdb.dbo.sysutility_ucp_mi_volume_space_health_internal(physical_server_name, server_instance_name, volume_device_id, set_number, processing_time
,health_state)
SELECT CAST(svr.ComputerNamePhysicalNetBIOS AS SYSNAME),
CAST(svr.Name AS SYSNAME),
vol.volume_device_id,
@new_set_number,
svr.processing_time,
CASE WHEN (@over_utilize_type = ISNULL(vu.utilization_type, 0))
THEN 3 -- over utilized
WHEN (@under_utilize_type = ISNULL(vu.utilization_type, 0))
THEN 2 -- under utilized
ELSE 1 -- healthy
END
FROM msdb.dbo.sysutility_ucp_instances AS svr
INNER JOIN msdb.dbo.sysutility_ucp_volumes AS vol ON vol.physical_server_name = svr.ComputerNamePhysicalNetBIOS
LEFT JOIN volume_utilization vu ON vol.physical_server_name = vu.physical_server_name AND vol.volume_device_id = vu.volume_device_id
-- Computes the processor health state for the computer.
-- Cache view data into temp table
SELECT *
INTO #computer_policies
FROM dbo.sysutility_ucp_computer_policies
-- Get the computer cpu utilization based on processor violating the health policy
-- Mark the computer as unhealthy if processor violate the policy
SELECT cp.physical_server_name as physical_server_name
, SUM(CASE WHEN cp.utilization_type = 1 THEN 1 ELSE 0 END) AS under_utilized_count
, SUM(CASE WHEN cp.utilization_type = 2 THEN 1 ELSE 0 END) AS over_utilized_count
INTO #computer_cpu_utilization
FROM #computer_policies cp
INNER JOIN dbo.sysutility_ucp_policy_violations pv
ON cp.policy_id = pv.policy_id AND cp.powershell_path = pv.target_query_expression
WHERE cp.resource_type = 3 -- processor_resource_type
AND cp.target_type = 1 -- computer_target_type
GROUP BY cp.physical_server_name
-- Insert new record
INSERT INTO msdb.dbo.sysutility_ucp_computer_cpu_health_internal(physical_server_name, set_number, processing_time, health_state)
SELECT c.physical_server_name
, @new_set_number
, c.processing_time,
CASE WHEN 0 < ISNULL(cu.over_utilized_count, 0) THEN
3 -- over utilized
WHEN 0 < ISNULL(cu.under_utilized_count, 0) THEN
2 -- under utilized
ELSE 1 -- healthy
END AS health_state
FROM msdb.dbo.sysutility_ucp_computers AS c
LEFT JOIN #computer_cpu_utilization cu
ON c.physical_server_name = cu.physical_server_name
END
GO
--*********************************************************************
-- Create procedure sp_sysutility_ucp_calculate_dac_health
-- Description: This is the top level procedure that computes all
-- the resource health states for the DAC.
--**********************************************************************
IF OBJECT_ID ('dbo.sp_sysutility_ucp_calculate_dac_health') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_calculate_dac_health', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_calculate_dac_health
END;
GO
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_calculate_dac_health', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_calculate_dac_health
@new_set_number INT
WITH EXECUTE AS OWNER
AS
BEGIN
-- Compute dac filegroup/log files health state
EXEC msdb.dbo.sp_sysutility_ucp_calculate_dac_file_space_health @new_set_number;
-- Compute dac health state
-- Insert new records
SELECT dd.dac_server_instance_name
, dd.dac_name
, SUM(CASE WHEN hs.health_state = 2 THEN 1 ELSE 0 END) AS under_utilized_count
, SUM(CASE WHEN hs.health_state = 3 THEN 1 ELSE 0 END) AS over_utilized_count
INTO #dac_volume_file_space_utilization
FROM msdb.dbo.sysutility_ucp_deployed_dacs AS dd
INNER JOIN msdb.dbo.sysutility_ucp_mi_volume_space_health_internal AS hs
ON hs.server_instance_name = dd.dac_server_instance_name
INNER JOIN (
SELECT server_instance_name, database_name, volume_device_id FROM sysutility_ucp_datafiles
UNION ALL
SELECT server_instance_name, database_name, volume_device_id FROM sysutility_ucp_logfiles
) AS df
ON df.volume_device_id = hs.volume_device_id
AND dd.dac_server_instance_name = df.server_instance_name
AND dd.dac_name = df.database_name
WHERE hs.set_number = @new_set_number
GROUP BY dd.dac_server_instance_name, dd.dac_name;
SELECT dd.dac_server_instance_name
, dd.dac_name
, SUM(CASE WHEN hs.health_state = 2 THEN 1 ELSE 0 END) AS under_utilized_count
, SUM(CASE WHEN hs.health_state = 3 THEN 1 ELSE 0 END) AS over_utilized_count
INTO #dac_computer_cpu_utilization
FROM msdb.dbo.sysutility_ucp_computer_cpu_health_internal AS hs
INNER JOIN msdb.dbo.sysutility_ucp_deployed_dacs AS dd
ON hs.physical_server_name = dd.dac_physical_server_name
WHERE hs.set_number = @new_set_number
GROUP BY dd.dac_server_instance_name, dd.dac_name;
SELECT hs.dac_server_instance_name
, hs.dac_name
, SUM(CASE WHEN health_state.val = 2 THEN 1 ELSE 0 END) AS under_utilized_count
, SUM(CASE WHEN health_state.val = 3 THEN 1 ELSE 0 END) AS over_utilized_count
INTO #dac_file_space_utilization
FROM msdb.dbo.sysutility_ucp_dac_file_space_health_internal hs
CROSS APPLY dbo.fn_sysutility_ucp_get_aggregated_health(hs.over_utilized_count, hs.under_utilized_count) health_state
WHERE hs.set_number = @new_set_number
GROUP BY hs.dac_server_instance_name, hs.dac_name;
-- Cache view data into temp table
SELECT *
INTO #dac_policies
FROM dbo.sysutility_ucp_dac_policies
-- Get the database cpu utilization based on processor violating the health policy
-- Mark the database as unhealthy if processor violate the policy
SELECT dp.dac_name
, dp.dac_server_instance_name
, SUM(CASE WHEN dp.utilization_type = 1 THEN 1 ELSE 0 END) AS under_utilized_count
, SUM(CASE WHEN dp.utilization_type = 2 THEN 1 ELSE 0 END) AS over_utilized_count
INTO #dac_cpu_utilizations
FROM #dac_policies AS dp
INNER JOIN dbo.sysutility_ucp_policy_violations pv
ON dp.policy_id = pv.policy_id AND dp.powershell_path = pv.target_query_expression
WHERE dp.resource_type = 3 -- processor_resource_type
AND dp.target_type = 5 -- database_target_type
GROUP BY dp.dac_name, dp.dac_server_instance_name
INSERT INTO msdb.dbo.sysutility_ucp_dac_health_internal(dac_name, dac_server_instance_name, set_number
, processing_time
, is_volume_space_over_utilized
, is_volume_space_under_utilized
, is_computer_processor_over_utilized
, is_computer_processor_under_utilized
, is_file_space_over_utilized
, is_file_space_under_utilized
, is_dac_processor_over_utilized
, is_dac_processor_under_utilized
, is_policy_overridden)
SELECT dd.dac_name
, dd.dac_server_instance_name
, @new_set_number
, dd.dac_processing_time
, vu.over_utilized_count AS dac_volume_space_over_utilized_count
, vu.under_utilized_count AS dac_volume_space_under_utilized_count
, cu.over_utilized_count AS dac_computer_cpu_over_utilized_count
, cu.under_utilized_count AS dac_computer_cpu_under_utilized_count
, su.over_utilized_count AS dac_file_space_over_utilized_count
, su.under_utilized_count AS dac_file_space_under_utilized_count
, ISNULL(du.over_utilized_count ,0) AS dac_cpu_over_utilized_count
, ISNULL(du.under_utilized_count ,0) AS dac_cpu_under_utilized_count
, pt.is_policy_overridden
FROM msdb.dbo.sysutility_ucp_deployed_dacs dd
LEFT JOIN #dac_cpu_utilizations du
ON dd.dac_name = du.dac_name AND dd.dac_server_instance_name = du.dac_server_instance_name
INNER JOIN #dac_volume_file_space_utilization AS vu
ON dd.dac_name = vu.dac_name AND dd.dac_server_instance_name = vu.dac_server_instance_name
INNER JOIN #dac_computer_cpu_utilization AS cu
ON dd.dac_name = cu.dac_name AND dd.dac_server_instance_name = cu.dac_server_instance_name
INNER JOIN #dac_file_space_utilization AS su
ON dd.dac_name = su.dac_name AND dd.dac_server_instance_name = su.dac_server_instance_name
INNER JOIN msdb.dbo.sysutility_ucp_dac_policy_type pt
ON dd.dac_name = pt.dac_name AND dd.dac_server_instance_name = pt.dac_server_instance_name;
END
GO
--*********************************************************************
-- Create procedure sp_sysutility_ucp_calculate_aggregated_dac_health
-- Description: This is the top level procedure that computes the health
-- statistics for the DAC. This uses the pre-computed health states for DAC's
-- The resulting health statistics are used in dashboard display
--**********************************************************************
IF OBJECT_ID ('dbo.sp_sysutility_ucp_calculate_aggregated_dac_health') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_calculate_aggregated_dac_health', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_calculate_aggregated_dac_health
END;
GO
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_calculate_aggregated_dac_health', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_calculate_aggregated_dac_health
@new_set_number INT
WITH EXECUTE AS OWNER
AS
BEGIN
-- DacCount
DECLARE @dac_count INT = 0
SELECT @dac_count = COUNT(*)
FROM msdb.dbo.sysutility_ucp_dac_health_internal hs
WHERE hs.set_number = @new_set_number
-- DacOverUtilizeCount
DECLARE @dac_over_utilize_count INT = 0
SELECT @dac_over_utilize_count = COUNT(*)
FROM msdb.dbo.sysutility_ucp_dac_health_internal hs
WHERE hs.set_number = @new_set_number AND
(0 != hs.is_dac_processor_over_utilized OR
0 != hs.is_computer_processor_over_utilized OR
0 != hs.is_file_space_over_utilized OR
0 != hs.is_volume_space_over_utilized)
-- DacUnderUtilizeCount
DECLARE @dac_under_utilize_count INT = 0
SELECT @dac_under_utilize_count = COUNT(*)
FROM msdb.dbo.sysutility_ucp_dac_health_internal hs
WHERE hs.set_number = @new_set_number AND
(0 != hs.is_dac_processor_under_utilized OR
0 != hs.is_computer_processor_under_utilized OR
0 != hs.is_file_space_under_utilized OR
0 != hs.is_volume_space_under_utilized)
AND 0 = hs.is_dac_processor_over_utilized
AND 0 = hs.is_computer_processor_over_utilized
AND 0 = hs.is_file_space_over_utilized
AND 0 = hs.is_volume_space_over_utilized
-- DacUnhealthyCount
DECLARE @dac_unhealthy_count INT = 0
SELECT @dac_unhealthy_count = @dac_over_utilize_count + @dac_under_utilize_count;
-- DacHealthyCount
DECLARE @dac_healthy_count INT = 0
SELECT @dac_healthy_count = COUNT(*)
FROM msdb.dbo.sysutility_ucp_dac_health_internal hs
WHERE hs.set_number = @new_set_number
AND 0 = hs.is_dac_processor_under_utilized
AND 0 = hs.is_computer_processor_under_utilized
AND 0 = hs.is_file_space_under_utilized
AND 0 = hs.is_volume_space_under_utilized
AND 0 = hs.is_dac_processor_over_utilized
AND 0 = hs.is_computer_processor_over_utilized
AND 0 = hs.is_file_space_over_utilized
AND 0 = hs.is_volume_space_over_utilized
-- Insert new record
INSERT INTO msdb.dbo.sysutility_ucp_aggregated_dac_health_internal(set_number
, dac_count
, dac_healthy_count
, dac_unhealthy_count
, dac_over_utilize_count
, dac_under_utilize_count
, dac_on_over_utilized_computer_count
, dac_on_under_utilized_computer_count
, dac_with_files_on_over_utilized_volume_count
, dac_with_files_on_under_utilized_volume_count
, dac_with_over_utilized_file_count
, dac_with_under_utilized_file_count
, dac_with_over_utilized_processor_count
, dac_with_under_utilized_processor_count)
SELECT @new_set_number
, @dac_count
, @dac_healthy_count
, @dac_unhealthy_count
, @dac_over_utilize_count
, @dac_under_utilize_count
, ISNULL(SUM(CASE WHEN 0 < hs.is_computer_processor_over_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_computer_processor_under_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_volume_space_over_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_volume_space_under_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_file_space_over_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_file_space_under_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_dac_processor_over_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_dac_processor_under_utilized THEN 1 ELSE 0 END), 0)
FROM msdb.dbo.sysutility_ucp_dac_health_internal hs
WHERE hs.set_number = @new_set_number
END
GO
--*********************************************************************
-- Create procedure sp_sysutility_ucp_calculate_mi_health
-- Description: This is the top level procedure that computes all
-- the resource health states for the MI.
--**********************************************************************
IF OBJECT_ID ('dbo.sp_sysutility_ucp_calculate_mi_health') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_calculate_mi_health', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_calculate_mi_health
END;
GO
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_calculate_mi_health', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_calculate_mi_health
@new_set_number INT
WITH EXECUTE AS OWNER
AS
BEGIN
-- Compute managed instance database health state
EXEC msdb.dbo.sp_sysutility_ucp_calculate_mi_file_space_health @new_set_number;
-- Compute managed instance health state
-- Insert new record
SELECT hs.server_instance_name AS server_instance_name,
SUM(CASE WHEN health_state.val = 2 THEN 1 ELSE 0 END) AS under_utilized_count,
SUM(CASE WHEN health_state.val = 3 THEN 1 ELSE 0 END) AS over_utilized_count
INTO #instance_file_space_utilization
FROM msdb.dbo.sysutility_ucp_mi_file_space_health_internal as hs
CROSS APPLY msdb.dbo.fn_sysutility_ucp_get_aggregated_health(hs.over_utilized_count, hs.under_utilized_count) as health_state
WHERE hs.set_number = @new_set_number
GROUP BY hs.server_instance_name;
SELECT sv.Name AS server_instance_name,
SUM(CASE WHEN hs.health_state = 2 THEN 1 ELSE 0 END) AS under_utilized_count,
SUM(CASE WHEN hs.health_state = 3 THEN 1 ELSE 0 END) AS over_utilized_count
INTO #instance_computer_cpu_utilization
FROM msdb.dbo.sysutility_ucp_computer_cpu_health_internal AS hs
INNER JOIN msdb.dbo.sysutility_ucp_instances AS sv
ON hs.physical_server_name = sv.ComputerNamePhysicalNetBIOS
WHERE hs.set_number = @new_set_number
GROUP BY sv.Name;
SELECT hs.server_instance_name AS server_instance_name,
SUM(CASE WHEN hs.health_state = 2 THEN 1 ELSE 0 END) AS under_utilized_count,
SUM(CASE WHEN hs.health_state = 3 THEN 1 ELSE 0 END) AS over_utilized_count
INTO #instance_volume_file_space_utilization
FROM msdb.dbo.sysutility_ucp_mi_volume_space_health_internal AS hs
INNER JOIN (
SELECT server_instance_name, database_name, volume_device_id FROM dbo.sysutility_ucp_datafiles
UNION ALL
SELECT server_instance_name, database_name, volume_device_id FROM dbo.sysutility_ucp_logfiles
) AS df
ON hs.volume_device_id = df.volume_device_id AND hs.server_instance_name = df.server_instance_name
WHERE hs.set_number = @new_set_number
GROUP BY hs.server_instance_name;
-- Cache view data into temp table
SELECT *
INTO #instance_policies
FROM dbo.sysutility_ucp_instance_policies
-- Get the MI cpu utilization based on processor violating the health policy
-- Mark the instance as unhealthy if processor violate the policy
SELECT ip.server_instance_name AS server_instance_name
, SUM(CASE WHEN ip.utilization_type = 1 THEN 1 ELSE 0 END) AS under_utilized_count
, SUM(CASE WHEN ip.utilization_type = 2 THEN 1 ELSE 0 END) AS over_utilized_count
INTO #instance_cpu_utilization
FROM #instance_policies ip
INNER JOIN dbo.sysutility_ucp_policy_violations pv
ON ip.policy_id = pv.policy_id AND ip.powershell_path = pv.target_query_expression
WHERE ip.resource_type = 3 -- processor_resource_type
AND ip.target_type = 4 -- instance_target_type
GROUP BY ip.server_instance_name
INSERT INTO msdb.dbo.sysutility_ucp_mi_health_internal(mi_name, set_number
, processing_time
, is_volume_space_over_utilized
, is_volume_space_under_utilized
, is_computer_processor_over_utilized
, is_computer_processor_under_utilized
, is_file_space_over_utilized
, is_file_space_under_utilized
, is_mi_processor_over_utilized
, is_mi_processor_under_utilized
, is_policy_overridden)
SELECT CAST(sv.Name AS SYSNAME) mi_name
, @new_set_number
, sv.processing_time
, vu.over_utilized_count AS mi_volume_space_over_utilized_count
, vu.under_utilized_count AS mi_volume_space_under_utilized_count
, cu.over_utilized_count AS mi_computer_cpu_over_utilized_count
, cu.under_utilized_count AS mi_computer_cpu_under_utilized_count
, su.over_utilized_count AS mi_file_space_over_utilized_count
, su.under_utilized_count AS mi_file_space_under_utilized_count
, ISNULL(iu.over_utilized_count ,0) AS mi_cpu_over_utilized_count
, ISNULL(iu.under_utilized_count ,0) AS mi_cpu_under_utilized_count
, pt.is_policy_overridden
FROM msdb.dbo.sysutility_ucp_managed_instances AS mi
INNER JOIN msdb.dbo.sysutility_ucp_instances AS sv ON sv.Name = mi.instance_name
LEFT OUTER JOIN #instance_cpu_utilization AS iu ON sv.Name = iu.server_instance_name
INNER JOIN #instance_volume_file_space_utilization AS vu ON sv.Name = vu.server_instance_name
INNER JOIN #instance_computer_cpu_utilization AS cu ON sv.Name = cu.server_instance_name
INNER JOIN #instance_file_space_utilization AS su ON sv.Name = su.server_instance_name
INNER JOIN msdb.dbo.sysutility_ucp_instance_policy_type AS pt ON sv.Name = pt.server_instance_name;
END
GO
--*********************************************************************
-- Create procedure sp_sysutility_ucp_calculate_aggregated_mi_health
-- Description: This is the top level procedure that computes the health
-- statistics for the MI. This uses the pre-computed health states for MI's
-- The resulting health statistics are used in dashboard display
--**********************************************************************
IF OBJECT_ID ('dbo.sp_sysutility_ucp_calculate_aggregated_mi_health') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_calculate_aggregated_mi_health', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_calculate_aggregated_mi_health
END;
GO
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_calculate_aggregated_mi_health', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_calculate_aggregated_mi_health
@new_set_number INT
WITH EXECUTE AS OWNER
AS
BEGIN
-- ManagedInstanceCount
DECLARE @mi_count INT = 0
SELECT @mi_count = COUNT(*)
FROM msdb.dbo.sysutility_ucp_mi_health_internal hs
WHERE hs.set_number = @new_set_number
-- ManagedInstanceOverUtilizeCount
DECLARE @mi_over_utilize_count INT = 0
SELECT @mi_over_utilize_count = COUNT(*)
FROM msdb.dbo.sysutility_ucp_mi_health_internal hs
WHERE hs.set_number = @new_set_number AND
(0 != hs.is_volume_space_over_utilized OR
0 != hs.is_computer_processor_over_utilized OR
0 != hs.is_file_space_over_utilized OR
0 != hs.is_mi_processor_over_utilized)
-- ManagedInstanceUnderUtilizeCount
DECLARE @mi_under_utilize_count INT = 0
SELECT @mi_under_utilize_count = COUNT(*)
FROM msdb.dbo.sysutility_ucp_mi_health_internal hs
WHERE hs.set_number = @new_set_number AND
(0 != hs.is_volume_space_under_utilized OR
0 != hs.is_computer_processor_under_utilized OR
0 != hs.is_file_space_under_utilized OR
0 != hs.is_mi_processor_under_utilized)
AND 0 = hs.is_volume_space_over_utilized
AND 0 = hs.is_computer_processor_over_utilized
AND 0 = hs.is_file_space_over_utilized
AND 0 = hs.is_mi_processor_over_utilized
-- ManagedInstanceUnhealthyCount
DECLARE @mi_unhealthy_count INT = 0
SELECT @mi_unhealthy_count = @mi_over_utilize_count + @mi_under_utilize_count
-- ManagedInstanceHealthyCount
DECLARE @mi_healthy_count INT = 0
SELECT @mi_healthy_count = COUNT(*)
FROM msdb.dbo.sysutility_ucp_mi_health_internal hs
WHERE hs.set_number = @new_set_number
AND 0 = hs.is_volume_space_under_utilized
AND 0 = hs.is_computer_processor_under_utilized
AND 0 = hs.is_file_space_under_utilized
AND 0 = hs.is_mi_processor_under_utilized
AND 0 = hs.is_volume_space_over_utilized
AND 0 = hs.is_computer_processor_over_utilized
AND 0 = hs.is_file_space_over_utilized
AND 0 = hs.is_mi_processor_over_utilized
-- Insert new record
INSERT INTO msdb.dbo.sysutility_ucp_aggregated_mi_health_internal(set_number
, mi_count
, mi_healthy_count
, mi_unhealthy_count
, mi_over_utilize_count
, mi_under_utilize_count
, mi_on_over_utilized_computer_count
, mi_on_under_utilized_computer_count
, mi_with_files_on_over_utilized_volume_count
, mi_with_files_on_under_utilized_volume_count
, mi_with_over_utilized_file_count
, mi_with_under_utilized_file_count
, mi_with_over_utilized_processor_count
, mi_with_under_utilized_processor_count)
SELECT @new_set_number
, @mi_count
, @mi_healthy_count
, @mi_unhealthy_count
, @mi_over_utilize_count
, @mi_under_utilize_count
, ISNULL(SUM(CASE WHEN 0 < hs.is_computer_processor_over_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_computer_processor_under_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_volume_space_over_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_volume_space_under_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_file_space_over_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_file_space_under_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_mi_processor_over_utilized THEN 1 ELSE 0 END), 0)
, ISNULL(SUM(CASE WHEN 0 < hs.is_mi_processor_under_utilized THEN 1 ELSE 0 END), 0)
FROM msdb.dbo.sysutility_ucp_mi_health_internal hs
WHERE hs.set_number = @new_set_number
END
GO
--**********************************************************************
-- Create procedure sp_sysutility_ucp_calculate_health
-- Procedure description:
-- This SP computes the health state of the utility resources based on the
-- policy evaluation results. The scheduled job runs the policies which evaluate
-- the resource for under and over utilization. The health state on the rollup object
-- are then determined by aggregating the health state of the underlying objects.
-- Following are the resource on which health states determined
-- 1. DAC / Server processor
-- 2. File storage space
-- 3. Volume storage space
-- 4. Computer processor
--**********************************************************************
IF OBJECT_ID ('dbo.sp_sysutility_ucp_calculate_health') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_calculate_health', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_calculate_health
END;
GO
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_calculate_health', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE dbo.sp_sysutility_ucp_calculate_health
WITH EXECUTE AS OWNER
AS
BEGIN
SET NOCOUNT ON;
-- Snapshot isolation prevents the nightly purge jobs that delete much older data from blocking us.
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
DECLARE @new_set_number INT
DECLARE @myTableVar table(next_health_state_id INT);
DECLARE @task_start_time DATETIME;
DECLARE @task_elapsed_ms INT;
-- get the "latest" set-number. We want all the health_state tables to
-- reflect the same point in time, and we achieve this by using a single
-- set_number column in each of the tables. At any point of time, we should
-- be using the entries from the table which correspond to the latest_health_state_id
-- value in the sysutility_ucp_processing_state_internal table
UPDATE msdb.dbo.sysutility_ucp_processing_state_internal
SET next_health_state_id = next_health_state_id + 1
OUTPUT INSERTED.next_health_state_id INTO @myTableVar;
SELECT @new_set_number = next_health_state_id
FROM @myTableVar;
-- Fetch the violations for health polices from latest policy evaluation
-- and cache them in the intermediate table. All the health state queries
-- reference this table to optimize performance
SET @task_start_time = GETUTCDATE();
EXEc dbo.sp_sysutility_ucp_get_policy_violations
SET @task_elapsed_ms = DATEDIFF (ms, @task_start_time, GETUTCDATE());
RAISERROR ('sp_sysutility_ucp_get_policy_violations completed in %d ms', 0, 1, @task_elapsed_ms);
SET @task_start_time = GETUTCDATE();
-- Identify filegroups that have a policy violation. (i.e.) all files in the filegroup
-- should have violated the same policy. Logfiles are considered to belong to a
-- fake filegroup with name=N''
-- We will use this information in subsequent calls
EXEC dbo.sp_sysutility_ucp_calculate_filegroups_with_policy_violations @new_set_number
SET @task_elapsed_ms = DATEDIFF (ms, @task_start_time, GETUTCDATE());
RAISERROR ('sp_sysutility_ucp_calculate_filegroups_with_policy_violations completed in %d ms', 0, 1, @task_elapsed_ms);
SET @task_start_time = GETUTCDATE();
-- Compute computer health state
EXEC sp_sysutility_ucp_calculate_computer_health @new_set_number
SET @task_elapsed_ms = DATEDIFF (ms, @task_start_time, GETUTCDATE());
RAISERROR ('sp_sysutility_ucp_calculate_computer_health completed in %d ms', 0, 1, @task_elapsed_ms);
SET @task_start_time = GETUTCDATE();
-- Compute dac health state
EXEC msdb.dbo.sp_sysutility_ucp_calculate_dac_health @new_set_number
SET @task_elapsed_ms = DATEDIFF (ms, @task_start_time, GETUTCDATE());
RAISERROR ('sp_sysutility_ucp_calculate_dac_health completed in %d ms', 0, 1, @task_elapsed_ms);
SET @task_start_time = GETUTCDATE();
-- Compute dac dashboard health stats
EXEC msdb.dbo.sp_sysutility_ucp_calculate_aggregated_dac_health @new_set_number
SET @task_elapsed_ms = DATEDIFF (ms, @task_start_time, GETUTCDATE());
RAISERROR ('sp_sysutility_ucp_calculate_aggregated_dac_health completed in %d ms', 0, 1, @task_elapsed_ms);
SET @task_start_time = GETUTCDATE();
-- Compute managed instance health state
EXEC msdb.dbo.sp_sysutility_ucp_calculate_mi_health @new_set_number
SET @task_elapsed_ms = DATEDIFF (ms, @task_start_time, GETUTCDATE());
RAISERROR ('sp_sysutility_ucp_calculate_mi_health completed in %d ms', 0, 1, @task_elapsed_ms);
SET @task_start_time = GETUTCDATE();
-- Compute managed instance dashboard health stats
EXEC msdb.dbo.sp_sysutility_ucp_calculate_aggregated_mi_health @new_set_number
SET @task_elapsed_ms = DATEDIFF (ms, @task_start_time, GETUTCDATE());
RAISERROR ('sp_sysutility_ucp_calculate_aggregated_mi_health completed in %d ms', 0, 1, @task_elapsed_ms);
SET @task_start_time = GETUTCDATE();
-- Update the config table with the new set_number
UPDATE msdb.dbo.sysutility_ucp_processing_state_internal
SET latest_health_state_id = @new_set_number
-- Delete the old sets
SET @task_start_time = GETUTCDATE();
DELETE FROM msdb.dbo.sysutility_ucp_aggregated_mi_health_internal WHERE set_number < @new_set_number
DELETE FROM msdb.dbo.sysutility_ucp_mi_health_internal WHERE set_number < @new_set_number
DELETE FROM msdb.dbo.sysutility_ucp_aggregated_dac_health_internal WHERE set_number < @new_set_number
DELETE FROM msdb.dbo.sysutility_ucp_dac_health_internal WHERE set_number < @new_set_number
DELETE FROM msdb.dbo.sysutility_ucp_computer_cpu_health_internal WHERE set_number < @new_set_number
DELETE FROM msdb.dbo.sysutility_ucp_mi_volume_space_health_internal WHERE set_number < @new_set_number
DELETE FROM msdb.dbo.sysutility_ucp_mi_database_health_internal WHERE set_number < @new_set_number
DELETE FROM msdb.dbo.sysutility_ucp_mi_file_space_health_internal WHERE set_number < @new_set_number
DELETE FROM msdb.dbo.sysutility_ucp_dac_file_space_health_internal WHERE set_number < @new_set_number
DELETE FROM msdb.dbo.sysutility_ucp_filegroups_with_policy_violations_internal WHERE set_number < @new_set_number
SET @task_elapsed_ms = DATEDIFF (ms, @task_start_time, GETUTCDATE());
RAISERROR ('Deleted older sets in %d ms', 0, 1, @task_elapsed_ms);
END
GO
IF OBJECT_ID ('dbo.sp_sysutility_ucp_configure_policies') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure dbo.sp_sysutility_ucp_configure_policies', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_configure_policies
END;
GO
RAISERROR ('Creating procedure dbo.sp_sysutility_ucp_configure_policies', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_configure_policies]
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @condition_id INT
DECLARE @object_set_id INT
DECLARE @target_set_id INT
DECLARE @policy_id INT
DECLARE @computer_urn NVARCHAR(4000)
DECLARE @dac_urn NVARCHAR(4000)
DECLARE @server_urn NVARCHAR(4000)
DECLARE @start DATETIME
SELECT @start = getdate()
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Delete existing Policies, Conditions, objectSets and Schedule
-------------------------------------------------------------------------------------------------------------------------------------------------------------
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityComputerProcessorOverUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityComputerProcessorOverUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityComputerProcessorOverUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityComputerProcessorOverUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityComputerProcessorOverUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityComputerProcessorOverUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityComputerProcessorOverUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityComputerProcessorOverUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityComputerProcessorOverUtilizationCondition'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityComputerProcessorOverUtilizationTargetCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityComputerProcessorOverUtilizationTargetCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityComputerProcessorOverUtilizationTargetCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityComputerProcessorUnderUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityComputerProcessorUnderUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityComputerProcessorUnderUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityComputerProcessorUnderUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityComputerProcessorUnderUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityComputerProcessorUnderUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityComputerProcessorUnderUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityComputerProcessorUnderUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityComputerProcessorUnderUtilizationCondition'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityComputerProcessorUnderUtilizationTargetCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityComputerProcessorUnderUtilizationTargetCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityComputerProcessorUnderUtilizationTargetCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityDacDataFileSpaceOverUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacDataFileSpaceOverUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityDacDataFileSpaceOverUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityDacDataFileSpaceOverUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacDataFileSpaceOverUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityDacDataFileSpaceOverUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityDacDataFileSpaceOverUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacDataFileSpaceOverUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityDacDataFileSpaceOverUtilizationCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityDacDataFileSpaceUnderUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacDataFileSpaceUnderUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityDacDataFileSpaceUnderUtilizationCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityDacLogFileSpaceOverUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacLogFileSpaceOverUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityDacLogFileSpaceOverUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityDacLogFileSpaceOverUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacLogFileSpaceOverUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityDacLogFileSpaceOverUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityDacLogFileSpaceOverUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacLogFileSpaceOverUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityDacLogFileSpaceOverUtilizationCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityDacLogFileSpaceUnderUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacLogFileSpaceUnderUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityDacLogFileSpaceUnderUtilizationCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityServerDataFileSpaceOverUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerDataFileSpaceOverUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityServerDataFileSpaceOverUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityServerDataFileSpaceOverUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerDataFileSpaceOverUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityServerDataFileSpaceOverUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityServerDataFileSpaceOverUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerDataFileSpaceOverUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityServerDataFileSpaceOverUtilizationCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityServerDataFileSpaceUnderUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerDataFileSpaceUnderUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityServerDataFileSpaceUnderUtilizationCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityServerLogFileSpaceOverUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerLogFileSpaceOverUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityServerLogFileSpaceOverUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityServerLogFileSpaceOverUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerLogFileSpaceOverUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityServerLogFileSpaceOverUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityServerLogFileSpaceOverUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerLogFileSpaceOverUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityServerLogFileSpaceOverUtilizationCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityServerLogFileSpaceUnderUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerLogFileSpaceUnderUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityServerLogFileSpaceUnderUtilizationCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityServerProcessorOverUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerProcessorOverUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityServerProcessorOverUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityServerProcessorOverUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerProcessorOverUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityServerProcessorOverUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityServerProcessorOverUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerProcessorOverUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityServerProcessorOverUtilizationCondition'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityServerProcessorOverUtilizationTargetCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerProcessorOverUtilizationTargetCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityServerProcessorOverUtilizationTargetCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityServerProcessorUnderUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerProcessorUnderUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityServerProcessorUnderUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityServerProcessorUnderUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerProcessorUnderUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityServerProcessorUnderUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityServerProcessorUnderUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerProcessorUnderUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityServerProcessorUnderUtilizationCondition'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityServerProcessorUnderUtilizationTargetCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerProcessorUnderUtilizationTargetCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityServerProcessorUnderUtilizationTargetCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityDacProcessorOverUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacProcessorOverUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityDacProcessorOverUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityDacProcessorOverUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacProcessorOverUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityDacProcessorOverUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityDacProcessorOverUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacProcessorOverUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityDacProcessorOverUtilizationCondition'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityDacProcessorOverUtilizationTargetCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacProcessorOverUtilizationTargetCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityDacProcessorOverUtilizationTargetCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityDacProcessorUnderUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacProcessorUnderUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityDacProcessorUnderUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityDacProcessorUnderUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacProcessorUnderUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityDacProcessorUnderUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityDacProcessorUnderUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacProcessorUnderUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityDacProcessorUnderUtilizationCondition'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityDacProcessorUnderUtilizationTargetCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacProcessorUnderUtilizationTargetCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityDacProcessorUnderUtilizationTargetCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityVolumeSpaceOverUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityVolumeSpaceOverUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityVolumeSpaceOverUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityVolumeSpaceOverUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityVolumeSpaceOverUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityVolumeSpaceOverUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityVolumeSpaceOverUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityVolumeSpaceOverUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityVolumeSpaceOverUtilizationCondition'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityVolumeSpaceOverUtilizationTargetCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityVolumeSpaceOverUtilizationTargetCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityVolumeSpaceOverUtilizationTargetCondition'
END
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'UtilityVolumeSpaceUnderUtilizationPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityVolumeSpaceUnderUtilizationPolicy', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_policy @name=N'UtilityVolumeSpaceUnderUtilizationPolicy'
END
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'UtilityVolumeSpaceUnderUtilizationPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityVolumeSpaceUnderUtilizationPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'UtilityVolumeSpaceUnderUtilizationPolicy_ObjectSet'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityVolumeSpaceUnderUtilizationCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityVolumeSpaceUnderUtilizationCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityVolumeSpaceUnderUtilizationCondition'
END
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=N'UtilityVolumeSpaceUnderUtilizationTargetCondition')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityVolumeSpaceUnderUtilizationTargetCondition', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_condition @name=N'UtilityVolumeSpaceUnderUtilizationTargetCondition'
END
IF EXISTS(SELECT COUNT(*) FROM msdb.dbo.sysutility_ucp_health_policies_internal)
BEGIN
DELETE FROM msdb.dbo.sysutility_ucp_health_policies_internal
END
IF EXISTS(SELECT schedule_id FROM msdb.dbo.sysschedules WHERE name=N'UtilityResourceHealthStateSchedule')
BEGIN
EXEC msdb.dbo.sp_delete_schedule @schedule_name=N'UtilityResourceHealthStateSchedule', @force_delete=1
END
IF EXISTS (SELECT job_id FROM msdb.dbo.sysjobs_view WHERE name = N'Utility Resource Health State')
BEGIN
EXEC msdb.dbo.sp_delete_job @job_name=N'Utility Resource Health State', @delete_unused_schedule=1
END
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityComputerProcessorOverUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityComputerProcessorOverUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the CPU overutilization policy is satisfied for a computer that hosts a managed instance of SQL Server. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'Computer', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityComputerProcessorOverUtilizationCondition', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityComputerProcessorOverUtilizationTargetCondition',
@description=N'The SQL Server Utility condition that is used to determine whether the CPU overutilization policy is violated for a computer that hosts a managed instance of SQL Server. This condition is used by the utility control point to query the computers.',
@facet=N'Computer', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GT</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityComputerProcessorOverUtilizationTargetCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityComputerProcessorUnderUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityComputerProcessorUnderUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the CPU underutilization policy is satisfied for a computer that hosts a managed instance of SQL Server. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'Computer', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityComputerProcessorUnderUtilizationCondition', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityComputerProcessorUnderUtilizationTargetCondition',
@description=N'The SQL Server Utility condition that is used to determine whether the CPU underutilization policy is violated for a computer that hosts a managed instance of SQL Server. This condition is used by the utility control point to query the computers.',
@facet=N'Computer', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LT</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityComputerProcessorUnderUtilizationTargetCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacDataFileSpaceOverUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityDacDataFileSpaceOverUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the data file space overutilization policy is satisfied for a deployed data-tier application. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'IDataFilePerformanceFacet', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>SpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacDataFileSpaceOverUtilizationCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacDataFileSpaceUnderUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityDacDataFileSpaceUnderUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the data file space underutilization policy is satisfied for a deployed data-tier application. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'IDataFilePerformanceFacet', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>SpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacDataFileSpaceUnderUtilizationCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacLogFileSpaceOverUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityDacLogFileSpaceOverUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the log file space overutilization policy is satisfied for a deployed data-tier application. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'ILogFilePerformanceFacet', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>SpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacLogFileSpaceOverUtilizationCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacLogFileSpaceUnderUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityDacLogFileSpaceUnderUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the log file space underutilization policy is satisfied for a deployed data-tier application. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'ILogFilePerformanceFacet', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>SpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacLogFileSpaceUnderUtilizationCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerDataFileSpaceOverUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityServerDataFileSpaceOverUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the data file space overutilization policy is satisfied for a managed instance of SQL Server. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'IDataFilePerformanceFacet', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>SpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerDataFileSpaceOverUtilizationCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerDataFileSpaceUnderUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityServerDataFileSpaceUnderUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the data file space underutilization policy is satisfied for a managed instance of SQL Server. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'IDataFilePerformanceFacet', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>SpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerDataFileSpaceUnderUtilizationCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerLogFileSpaceOverUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityServerLogFileSpaceOverUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the log file space overutilization policy is satisfied for a managed instance of SQL Server. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'ILogFilePerformanceFacet', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>SpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerLogFileSpaceOverUtilizationCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerLogFileSpaceUnderUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityServerLogFileSpaceUnderUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the log file space underutilization policy is satisfied for a managed instance of SQL Server. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'ILogFilePerformanceFacet', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>SpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerLogFileSpaceUnderUtilizationCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerProcessorOverUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityServerProcessorOverUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the CPU overutilization policy is satisfied for a managed instance of SQL Server. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'Server', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUsage</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerProcessorOverUtilizationCondition', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityServerProcessorOverUtilizationTargetCondition',
@description=N'The SQL Server Utility condition that is used to determine whether the CPU overutilization policy is violated for a managed instance of SQL Server. This condition is used by the utility control point to query the managed instances of SQL Server.',
@facet=N'Server', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GT</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUsage</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerProcessorOverUtilizationTargetCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerProcessorUnderUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityServerProcessorUnderUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the CPU underutilization policy is satisfied for a managed instance of SQL Server. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'Server', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUsage</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerProcessorUnderUtilizationCondition', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityServerProcessorUnderUtilizationTargetCondition',
@description=N'The SQL Server Utility condition that is used to determine whether the CPU underutilization policy is violated for a managed instance of SQL Server. This condition is used by the utility control point to query the managed instances of SQL Server.',
@facet=N'Server', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LT</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUsage</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityServerProcessorUnderUtilizationTargetCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacProcessorOverUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityDacProcessorOverUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the CPU overutilization policy is satisfied for a deployed data-tier application. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'DeployedDac', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacProcessorOverUtilizationCondition', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityDacProcessorOverUtilizationTargetCondition',
@description=N'The SQL Server Utility condition that is used to determine whether the CPU overutilization policy is violated for a deployed data-tier application. This condition is used by the utility control point to query the deployed data-tier applications. ',
@facet=N'DeployedDac', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GT</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacProcessorOverUtilizationTargetCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacProcessorUnderUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityDacProcessorUnderUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the CPU underutilization policy is satisfied for a deployed data-tier application. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'DeployedDac', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacProcessorUnderUtilizationCondition', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityDacProcessorUnderUtilizationTargetCondition',
@description=N'The SQL Server Utility condition that is used to determine whether the CPU underutilization policy is violated for a deployed data-tier application. This condition is used by the utility control point to query the deployed data-tier applications. ',
@facet=N'DeployedDac', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LT</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ProcessorUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityDacProcessorUnderUtilizationTargetCondition', @marker=1
------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityVolumeSpaceOverUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityVolumeSpaceOverUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the volume space overutilization policy is satisfied for a computer that hosts a managed instance of SQL Server. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'Volume', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>TotalSpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityVolumeSpaceOverUtilizationCondition', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityVolumeSpaceOverUtilizationTargetCondition',
@description=N'The SQL Server Utility condition that is used to determine whether the volume space overutilization policy is violated for a computer that hosts a managed instance of SQL Server. This condition is used by the utility control point to query the volumes.',
@facet=N'Volume', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GT</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>TotalSpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>70</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityVolumeSpaceOverUtilizationTargetCondition', @marker=1
------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityVolumeSpaceUnderUtilizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityVolumeSpaceUnderUtilizationCondition',
@description=N'The SQL Server Utility condition that expresses when the volume space underutilization policy is satisfied for a computer that hosts a managed instance of SQL Server. The value that is used in the condition expression is set in SQL Server Utility Explorer.',
@facet=N'Volume', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>TotalSpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityVolumeSpaceUnderUtilizationCondition', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'UtilityVolumeSpaceUnderUtilizationTargetCondition',
@description=N'The SQL Server Utility condition that is used to determine whether the volume space underutilization policy is violated for a computer that hosts a managed instance of SQL Server. This condition is used by the utility control point to query the volumes. ',
@facet=N'Volume', @expression=N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>LT</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>TotalSpaceUtilization</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>', @is_name_condition=0, @obj_name=N'', @condition_id=@condition_id OUTPUT
Select @condition_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=N'UtilityVolumeSpaceUnderUtilizationTargetCondition', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityComputerProcessorOverUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityComputerProcessorOverUtilizationPolicy_ObjectSet', @facet=N'Computer', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityComputerProcessorOverUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityComputerProcessorOverUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Computer', @type=N'COMPUTER', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Computer', @level_name=N'Computer', @condition_name=N'UtilityComputerProcessorOverUtilizationTargetCondition', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityComputerProcessorOverUtilizationPolicy', @condition_name=N'UtilityComputerProcessorOverUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for CPU overutilization on a computer that hosts a managed instance of SQL Server.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityComputerProcessorOverUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityComputerProcessorOverUtilizationPolicy', @marker=1
SELECT @computer_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/Computer'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityComputerProcessorOverUtilizationPolicy',@rollup_object_type=3,@rollup_object_urn=@computer_urn,@target_type=1,@resource_type=3,@utilization_type=2,@utilization_threshold=70
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityComputerProcessorUnderUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityComputerProcessorUnderUtilizationPolicy_ObjectSet', @facet=N'Computer', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityComputerProcessorUnderUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityComputerProcessorUnderUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Computer', @type=N'COMPUTER', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Computer', @level_name=N'Computer', @condition_name=N'UtilityComputerProcessorUnderUtilizationTargetCondition', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityComputerProcessorUnderUtilizationPolicy', @condition_name=N'UtilityComputerProcessorUnderUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for CPU underutilization on a computer that hosts a managed instance of SQL Server.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityComputerProcessorUnderUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityComputerProcessorUnderUtilizationPolicy', @marker=1
SELECT @computer_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/Computer'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityComputerProcessorUnderUtilizationPolicy',@rollup_object_type=3,@rollup_object_urn=@computer_urn,@target_type=1,@resource_type=3,@utilization_type=1,@utilization_threshold=0
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacDataFileSpaceOverUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityDacDataFileSpaceOverUtilizationPolicy_ObjectSet', @facet=N'IDataFilePerformanceFacet', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacDataFileSpaceOverUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityDacDataFileSpaceOverUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Server/Database/FileGroup/File', @type=N'FILE', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/FileGroup/File', @level_name=N'File', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/FileGroup', @level_name=N'FileGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server', @level_name=N'Server', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityDacDataFileSpaceOverUtilizationPolicy', @condition_name=N'UtilityDacDataFileSpaceOverUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for data file space overutilization for a deployed data-tier application.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityDacDataFileSpaceOverUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacDataFileSpaceOverUtilizationPolicy', @marker=1
SELECT @dac_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/DeployedDac'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityDacDataFileSpaceOverUtilizationPolicy',@rollup_object_type=1,@rollup_object_urn=@dac_urn,@target_type=2,@resource_type=1,@utilization_type=2,@utilization_threshold=70
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacDataFileSpaceUnderUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy_ObjectSet', @facet=N'IDataFilePerformanceFacet', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Server/Database/FileGroup/File', @type=N'FILE', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/FileGroup/File', @level_name=N'File', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/FileGroup', @level_name=N'FileGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server', @level_name=N'Server', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy', @condition_name=N'UtilityDacDataFileSpaceUnderUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for data file space underutilization for a deployed data-tier application.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityDacDataFileSpaceUnderUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy', @marker=1
SELECT @dac_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/DeployedDac'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityDacDataFileSpaceUnderUtilizationPolicy',@rollup_object_type=1,@rollup_object_urn=@dac_urn,@target_type=2,@resource_type=1,@utilization_type=1,@utilization_threshold=0
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacLogFileSpaceOverUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityDacLogFileSpaceOverUtilizationPolicy_ObjectSet', @facet=N'ILogFilePerformanceFacet', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacLogFileSpaceOverUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityDacLogFileSpaceOverUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Server/Database/LogFile', @type=N'LOGFILE', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/LogFile', @level_name=N'LogFile', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server', @level_name=N'Server', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityDacLogFileSpaceOverUtilizationPolicy', @condition_name=N'UtilityDacLogFileSpaceOverUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for log file space overutilization for a deployed data-tier application.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityDacLogFileSpaceOverUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacLogFileSpaceOverUtilizationPolicy', @marker=1
SELECT @dac_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/DeployedDac'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityDacLogFileSpaceOverUtilizationPolicy',@rollup_object_type=1,@rollup_object_urn=@dac_urn,@target_type=3,@resource_type=1,@utilization_type=2,@utilization_threshold=70
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacLogFileSpaceUnderUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy_ObjectSet', @facet=N'ILogFilePerformanceFacet', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Server/Database/LogFile', @type=N'LOGFILE', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/LogFile', @level_name=N'LogFile', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server', @level_name=N'Server', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy', @condition_name=N'UtilityDacLogFileSpaceUnderUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for log file space underutilization for a deployed data-tier application.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityDacLogFileSpaceUnderUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy', @marker=1
SELECT @dac_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/DeployedDac'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityDacLogFileSpaceUnderUtilizationPolicy',@rollup_object_type=1,@rollup_object_urn=@dac_urn,@target_type=3,@resource_type=1,@utilization_type=1,@utilization_threshold=0
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerDataFileSpaceOverUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityServerDataFileSpaceOverUtilizationPolicy_ObjectSet', @facet=N'IDataFilePerformanceFacet', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerDataFileSpaceOverUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityServerDataFileSpaceOverUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Server/Database/FileGroup/File', @type=N'FILE', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/FileGroup/File', @level_name=N'File', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/FileGroup', @level_name=N'FileGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server', @level_name=N'Server', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityServerDataFileSpaceOverUtilizationPolicy', @condition_name=N'UtilityServerDataFileSpaceOverUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for data file space overutilization on a managed instance of SQL Server.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityServerDataFileSpaceOverUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerDataFileSpaceOverUtilizationPolicy', @marker=1
SELECT @server_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/Server'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityServerDataFileSpaceOverUtilizationPolicy',@rollup_object_type=2,@rollup_object_urn=@server_urn,@target_type=2,@resource_type=1,@utilization_type=2,@utilization_threshold=70
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerDataFileSpaceUnderUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy_ObjectSet', @facet=N'IDataFilePerformanceFacet', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Server/Database/FileGroup/File', @type=N'FILE', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/FileGroup/File', @level_name=N'File', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/FileGroup', @level_name=N'FileGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server', @level_name=N'Server', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy', @condition_name=N'UtilityServerDataFileSpaceUnderUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for data file space underutilization on a managed instance of SQL Server.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityServerDataFileSpaceUnderUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy', @marker=1
SELECT @server_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/Server'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityServerDataFileSpaceUnderUtilizationPolicy',@rollup_object_type=2,@rollup_object_urn=@server_urn,@target_type=2,@resource_type=1,@utilization_type=1,@utilization_threshold=0
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerLogFileSpaceOverUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityServerLogFileSpaceOverUtilizationPolicy_ObjectSet', @facet=N'ILogFilePerformanceFacet', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerLogFileSpaceOverUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityServerLogFileSpaceOverUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Server/Database/LogFile', @type=N'LOGFILE', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/LogFile', @level_name=N'LogFile', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server', @level_name=N'Server', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityServerLogFileSpaceOverUtilizationPolicy', @condition_name=N'UtilityServerLogFileSpaceOverUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for log file space overutilization on a managed instance of SQL Server.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityServerLogFileSpaceOverUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerLogFileSpaceOverUtilizationPolicy', @marker=1
SELECT @server_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/Server'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityServerLogFileSpaceOverUtilizationPolicy',@rollup_object_type=2,@rollup_object_urn=@server_urn,@target_type=3,@resource_type=1,@utilization_type=2,@utilization_threshold=70
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerLogFileSpaceUnderUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy_ObjectSet', @facet=N'ILogFilePerformanceFacet', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Server/Database/LogFile', @type=N'LOGFILE', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database/LogFile', @level_name=N'LogFile', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server', @level_name=N'Server', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy', @condition_name=N'UtilityServerLogFileSpaceUnderUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for log file space underutilization on a managed instance of SQL Server.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityServerLogFileSpaceUnderUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy', @marker=1
SELECT @server_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/Server'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityServerLogFileSpaceUnderUtilizationPolicy',@rollup_object_type=2,@rollup_object_urn=@server_urn,@target_type=3,@resource_type=1,@utilization_type=1,@utilization_threshold=0
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerProcessorOverUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityServerProcessorOverUtilizationPolicy_ObjectSet', @facet=N'Server', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerProcessorOverUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityServerProcessorOverUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Server', @type=N'SERVER', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server', @level_name=N'Server', @condition_name=N'UtilityServerProcessorOverUtilizationTargetCondition', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityServerProcessorOverUtilizationPolicy', @condition_name=N'UtilityServerProcessorOverUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for CPU overutilization on a managed instance of SQL Server.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityServerProcessorOverUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerProcessorOverUtilizationPolicy', @marker=1
SELECT @server_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/Server'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityServerProcessorOverUtilizationPolicy',@rollup_object_type=2,@rollup_object_urn=@server_urn,@target_type=4,@resource_type=3,@utilization_type=2,@utilization_threshold=70
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityServerProcessorUnderUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityServerProcessorUnderUtilizationPolicy_ObjectSet', @facet=N'Server', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityServerProcessorUnderUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityServerProcessorUnderUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Server', @type=N'SERVER', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Server', @level_name=N'Server', @condition_name=N'UtilityServerProcessorUnderUtilizationTargetCondition', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityServerProcessorUnderUtilizationPolicy', @condition_name=N'UtilityServerProcessorUnderUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for CPU underutilization on a managed instance of SQL Server.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityServerProcessorUnderUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityServerProcessorUnderUtilizationPolicy', @marker=1
SELECT @server_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/Server'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityServerProcessorUnderUtilizationPolicy',@rollup_object_type=2,@rollup_object_urn=@server_urn,@target_type=4,@resource_type=3,@utilization_type=1,@utilization_threshold=0
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacProcessorOverUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityDacProcessorOverUtilizationPolicy_ObjectSet', @facet=N'DeployedDac', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacProcessorOverUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityDacProcessorOverUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/DeployedDac', @type=N'DEPLOYEDDAC', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/DeployedDac', @level_name=N'DeployedDac', @condition_name=N'UtilityDacProcessorOverUtilizationTargetCondition', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityDacProcessorOverUtilizationPolicy', @condition_name=N'UtilityDacProcessorOverUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for CPU overutilization for a deployed data-tier application.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityDacProcessorOverUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacProcessorOverUtilizationPolicy', @marker=1
SELECT @dac_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/DeployedDac'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityDacProcessorOverUtilizationPolicy',@rollup_object_type=1,@rollup_object_urn=@dac_urn,@target_type=5,@resource_type=3,@utilization_type=2,@utilization_threshold=70
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityDacProcessorUnderUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityDacProcessorUnderUtilizationPolicy_ObjectSet', @facet=N'DeployedDac', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityDacProcessorUnderUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityDacProcessorUnderUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/DeployedDac', @type=N'DEPLOYEDDAC', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/DeployedDac', @level_name=N'DeployedDac', @condition_name=N'UtilityDacProcessorUnderUtilizationTargetCondition', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityDacProcessorUnderUtilizationPolicy', @condition_name=N'UtilityDacProcessorUnderUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for CPU underutilization for a deployed data-tier application.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityDacProcessorUnderUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityDacProcessorUnderUtilizationPolicy', @marker=1
SELECT @dac_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/DeployedDac'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityDacProcessorUnderUtilizationPolicy',@rollup_object_type=1,@rollup_object_urn=@dac_urn,@target_type=5,@resource_type=3,@utilization_type=1,@utilization_threshold=0
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityVolumeSpaceOverUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityVolumeSpaceOverUtilizationPolicy_ObjectSet', @facet=N'Volume', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityVolumeSpaceOverUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityVolumeSpaceOverUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Computer/Volume', @type=N'VOLUME', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Computer/Volume', @level_name=N'Volume', @condition_name=N'UtilityVolumeSpaceOverUtilizationTargetCondition', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Computer', @level_name=N'Computer', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityVolumeSpaceOverUtilizationPolicy', @condition_name=N'UtilityVolumeSpaceOverUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for volume space overutilization on a computer that hosts a managed instance of SQL Server.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityVolumeSpaceOverUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityVolumeSpaceOverUtilizationPolicy', @marker=1
SELECT @computer_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/Computer'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityVolumeSpaceOverUtilizationPolicy',@rollup_object_type=3,@rollup_object_urn=@computer_urn,@target_type=6,@resource_type=1,@utilization_type=2,@utilization_threshold=70
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- UtilityVolumeSpaceUnderUtilizationPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'UtilityVolumeSpaceUnderUtilizationPolicy_ObjectSet', @facet=N'Volume', @object_set_id=@object_set_id OUTPUT
Select @object_set_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'UtilityVolumeSpaceUnderUtilizationPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'UtilityVolumeSpaceUnderUtilizationPolicy_ObjectSet', @type_skeleton=N'Utility/Computer/Volume', @type=N'VOLUME', @enabled=True, @target_set_id=@target_set_id OUTPUT
Select @target_set_id
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Computer/Volume', @level_name=N'Volume', @condition_name=N'UtilityVolumeSpaceUnderUtilizationTargetCondition', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Utility/Computer', @level_name=N'Computer', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'UtilityVolumeSpaceUnderUtilizationPolicy', @condition_name=N'UtilityVolumeSpaceUnderUtilizationCondition', @policy_category=N'',
@description=N'The SQL Server Utility policy that checks for volume space underutilization on a computer that hosts a managed instance of SQL Server.',
@help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'UtilityVolumeSpaceUnderUtilizationPolicy_ObjectSet'
Select @policy_id
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'UtilityVolumeSpaceUnderUtilizationPolicy', @marker=1
SELECT @computer_urn = 'Utility[@Name='''+CONVERT(SYSNAME, SERVERPROPERTY(N'ServerName'))+''']/Computer'
EXEC msdb.dbo.sp_sysutility_ucp_add_policy @policy_name=N'UtilityVolumeSpaceUnderUtilizationPolicy',@rollup_object_type=3,@rollup_object_urn=@computer_urn,@target_type=6,@resource_type=1,@utilization_type=1,@utilization_threshold=0
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Update sysutility_ucp_health_policies_internal entries to system policies
-------------------------------------------------------------------------------------------------------------------------------------------------------------
IF EXISTS(SELECT COUNT(*) FROM msdb.dbo.sysutility_ucp_health_policies_internal)
BEGIN
UPDATE msdb.dbo.sysutility_ucp_health_policies_internal SET is_global_policy = 1
END
-- Compute default health states during UCP creation (boot strap scenario)
EXEC msdb.dbo.sp_sysutility_ucp_calculate_health
--**********************************************************************
-- Mark all newly created sp_sysutility* artifacts as system.
-- (code extracted and modified from "Mark system objects" in instdb.sql.)
--**********************************************************************
BEGIN
declare @name sysname;
declare newsysobjs cursor for select name from sys.objects where schema_id = 1 and name LIKE '%sysutility%' and create_date >= @start
open newsysobjs
fetch next from newsysobjs into @name
while @@fetch_status = 0
begin
Exec sp_MS_marksystemobject @name
fetch next from newsysobjs into @name
end
deallocate newsysobjs
END
END
GO
/*******************************************************************
Procedure to remove utility control point (UCP) from target SQL server instance
Following are the pre-requsite validations done by the procedure
a. The user executing the script has sysadmin role on target instance
b. The target instance must be a utility control point
c. There are no active enrolled managed instances in the UCP
The procedure handles cleanup of following UCP artifacts
1. Drops the MDW database if there are no system collection sets enabled;
else truncates the utility live, dimension and measure tables.
2. Update UCP configuration tables with default values
3. Drop all the resource health policies
4. Truncate utility health state tables in MSDB database
5. Remove the utility aggregation jobs
6. Remove the utility related registry keys
*******************************************************************/
IF OBJECT_ID(N'[dbo].[sp_sysutility_ucp_remove]') IS NOT NULL
BEGIN
RAISERROR('Dropping [dbo].[sp_sysutility_ucp_remove] procedure', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_ucp_remove];
END
GO
RAISERROR('Creating [dbo].[sp_sysutility_ucp_remove] procedure', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_remove]
WITH EXECUTE AS CALLER
AS
BEGIN
SET NOCOUNT ON;
---------------------------------------------------------------------
-- Validation Steps
---------------------------------------------------------------------
-- Validate the user running the script is sysadmin on the UCP instance
IF (1 != IS_SRVROLEMEMBER(N'sysadmin ', SUSER_NAME()))
BEGIN
RAISERROR(37008, -1, -1)
RETURN(1)
END
-- Validate the instance is UCP
IF (0 = (SELECT msdb.dbo.fn_sysutility_get_is_instance_ucp()))
BEGIN
RAISERROR(37009, -1, -1)
RETURN(1)
END
-- Validate all managed instances are un-enrolled
IF (0 < (SELECT COUNT(*) FROM [dbo].[sysutility_ucp_managed_instances]))
BEGIN
RAISERROR(37010, -1, -1)
RETURN(1)
END
---------------------------------------------------------------------
-- Remove UCP artifacts
---------------------------------------------------------------------
IF EXISTS (SELECT name FROM [master].[sys].[databases] WHERE name = N'sysutility_mdw')
BEGIN
-- Check whether there are other non-utility (DC system / custom) collection sets targeted to sysutility_mdw database
IF (0 = (SELECT COUNT(*) FROM [sysutility_mdw].[core].[source_info_internal] WHERE collection_set_uid != N'ABA37A22-8039-48C6-8F8F-39BFE0A195DF'))
BEGIN
-- Drop utility MDW database as there are no non-utility collection sets uploading data to this DB
ALTER DATABASE [sysutility_mdw] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [sysutility_mdw];
-- Delete MDW purge jobs
IF EXISTS (SELECT job_id FROM [dbo].[sysjobs_view] WHERE name = N'mdw_purge_data_[sysutility_mdw]')
BEGIN
EXEC [dbo].sp_delete_job @job_name=N'mdw_purge_data_[sysutility_mdw]', @delete_unused_schedule=1
END
END
ELSE
BEGIN
-- There are non-utility collection sets uploading data to mdw
-- so do not drop the MDW database; instead truncate utility tables to purge data
DECLARE @schema_name SYSNAME
DECLARE @table_name SYSNAME
DECLARE @expression NVARCHAR(MAX)
-- Truncate the dimension, measure and live tables in MDW database
DECLARE tables_cursor CURSOR FOR
SELECT object_schema, object_name
FROM [sysutility_mdw].[sysutility_ucp_misc].[utility_objects_internal]
WHERE sql_object_type = N'USER_TABLE'
AND utility_object_type IN (N'DIMENSION', N'MEASURE', N'LIVE')
OPEN tables_cursor;
FETCH NEXT FROM tables_cursor INTO @schema_name, @table_name
WHILE (@@FETCH_STATUS <> -1)
BEGIN
SET @expression = 'TRUNCATE TABLE [sysutility_mdw].' + QUOTENAME(@schema_name) + '.' + QUOTENAME(@table_name);
EXEC sp_executesql @expression;
FETCH NEXT FROM tables_cursor INTO @schema_name, @table_name
END;
CLOSE tables_cursor;
DEALLOCATE tables_cursor;
END
END
--###FP 1
---------------------------------------------------------------------
-- Truncate the utility tables in msdb database
-- Note: Do not truncate tables in which data is pre-shipped
---------------------------------------------------------------------
TRUNCATE TABLE [dbo].[sysutility_ucp_mi_health_internal];
TRUNCATE TABLE [dbo].[sysutility_ucp_aggregated_mi_health_internal];
TRUNCATE TABLE [dbo].[sysutility_ucp_mi_database_health_internal];
TRUNCATE TABLE [dbo].[sysutility_ucp_mi_volume_space_health_internal];
TRUNCATE TABLE [dbo].[sysutility_ucp_mi_file_space_health_internal];
TRUNCATE TABLE [dbo].[sysutility_ucp_dac_health_internal];
TRUNCATE TABLE [dbo].[sysutility_ucp_aggregated_dac_health_internal];
TRUNCATE TABLE [dbo].[sysutility_ucp_dac_file_space_health_internal];
TRUNCATE TABLE [dbo].[sysutility_ucp_computer_cpu_health_internal];
TRUNCATE TABLE [dbo].[sysutility_ucp_filegroups_with_policy_violations_internal];
TRUNCATE TABLE [dbo].[sysutility_ucp_policy_violations_internal];
TRUNCATE TABLE [dbo].[sysutility_ucp_snapshot_partitions_internal];
--###FP 2
---------------------------------------------------------------------
-- Delete utility aggregation jobs
---------------------------------------------------------------------
IF EXISTS (SELECT job_id FROM [dbo].[sysjobs_view] WHERE name = N'sysutility_get_views_data_into_cache_tables')
BEGIN
EXEC [dbo].sp_delete_job @job_name=N'sysutility_get_views_data_into_cache_tables', @delete_unused_schedule=1
END
IF EXISTS (SELECT job_id FROM [dbo].[sysjobs_view] WHERE name = N'sysutility_get_cache_tables_data_into_aggregate_tables_hourly')
BEGIN
EXEC [dbo].sp_delete_job @job_name=N'sysutility_get_cache_tables_data_into_aggregate_tables_hourly', @delete_unused_schedule=1
END
IF EXISTS (SELECT job_id FROM [dbo].[sysjobs_view] WHERE name = N'sysutility_get_cache_tables_data_into_aggregate_tables_daily')
BEGIN
EXEC [dbo].sp_delete_job @job_name=N'sysutility_get_cache_tables_data_into_aggregate_tables_daily', @delete_unused_schedule=1
END
--###FP 3
---------------------------------------------------------------------
-- Drop resource health policies, conditions and objectSets
---------------------------------------------------------------------
DECLARE @policy_name SYSNAME
DECLARE @health_policy_id INT
DECLARE @policy_id INT
DECLARE @object_set_id INT
DECLARE @condition_id INT
DECLARE @target_condition_id INT
DECLARE policies_cursor CURSOR FOR
SELECT policy_name, health_policy_id
FROM [dbo].[sysutility_ucp_policies]
OPEN policies_cursor;
FETCH NEXT FROM policies_cursor INTO @policy_name, @health_policy_id
WHILE (@@FETCH_STATUS <> -1)
BEGIN
SELECT @policy_id = policy_id
, @object_set_id = object_set_id
, @condition_id = condition_id
FROM [dbo].[syspolicy_policies]
WHERE name = @policy_name
-- Delete the policy
EXEC [dbo].sp_syspolicy_mark_system @type=N'POLICY', @object_id=@policy_id, @marker=0
EXEC [dbo].sp_syspolicy_delete_policy @policy_id=@policy_id
-- Get the target set condtions before deleting the object set
CREATE TABLE #target_conditions(condition_id INT);
INSERT INTO #target_conditions
SELECT condition_id
FROM [dbo].[syspolicy_target_sets] ts
, [dbo].[syspolicy_target_set_levels] tsl
WHERE ts.target_set_id = tsl.target_set_id
AND ts.object_set_id = @object_set_id
-- Delete the object set
EXEC [dbo].sp_syspolicy_mark_system @type=N'OBJECTSET', @object_id=@object_set_id, @marker=0
EXEC [dbo].sp_syspolicy_delete_object_set @object_set_id=@object_set_id
DECLARE target_conditions_cursor CURSOR FOR
SELECT condition_id
FROM #target_conditions
OPEN target_conditions_cursor;
FETCH NEXT FROM target_conditions_cursor INTO @target_condition_id
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@target_condition_id IS NOT NULL)
BEGIN
--- Delete the target set condition
EXEC [dbo].sp_syspolicy_mark_system @type=N'CONDITION', @object_id=@target_condition_id, @marker=0
EXEC [dbo].sp_syspolicy_delete_condition @condition_id=@target_condition_id
END
FETCH NEXT FROM target_conditions_cursor INTO @target_condition_id
END;
CLOSE target_conditions_cursor;
DEALLOCATE target_conditions_cursor;
DROP TABLE #target_conditions
--- Delete the check condition
EXEC [dbo].sp_syspolicy_mark_system @type=N'CONDITION', @object_id=@condition_id, @marker=0
EXEC [dbo].sp_syspolicy_delete_condition @condition_id=@condition_id
-- Delete the resource health policy
DELETE [dbo].[sysutility_ucp_health_policies_internal]
WHERE health_policy_id = @health_policy_id
FETCH NEXT FROM policies_cursor INTO @policy_name, @health_policy_id
END;
CLOSE policies_cursor;
DEALLOCATE policies_cursor;
--###FP 4
---------------------------------------------------------------------
-- Remove the utility related registry keys from the system
---------------------------------------------------------------------
-- Remove the UtilityVersion registry key value
DECLARE @utility_version nvarchar(1024)
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'UtilityVersion',
@utility_version OUTPUT
IF (@utility_version IS NOT NULL)
BEGIN
EXEC master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'UtilityVersion'
END
-- Remove the UcpName registry key value
DECLARE @utility_name nvarchar(1024)
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'UcpName',
@utility_name OUTPUT
IF (@utility_name IS NOT NULL)
BEGIN
EXEC master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'UcpName'
END
-- Remove the UcpFriendlyName registry key value
DECLARE @utility_friendly_name nvarchar(1024)
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'UcpFriendlyName',
@utility_friendly_name OUTPUT
IF (@utility_friendly_name IS NOT NULL)
BEGIN
EXEC master.dbo.xp_instance_regdeletevalue N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility',
N'UcpFriendlyName'
END
-- Remove the Utility registry key
EXEC master.dbo.xp_instance_regdeletekey N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\Utility'
--###FP 5
---------------------------------------------------------------------
-- Reset the processing state table to default values
---------------------------------------------------------------------
UPDATE [dbo].[sysutility_ucp_processing_state_internal]
SET latest_processing_time = SYSDATETIMEOFFSET(), latest_health_state_id = 0, next_health_state_id = 1
--###FP 6
---------------------------------------------------------------------
-- Update utility configuration table entries to default values
-- Note: Keep this cleanup as the last one as the script uses this
-- to check if the target instance is a UCP in the validation
---------------------------------------------------------------------
UPDATE [dbo].[sysutility_ucp_configuration_internal] SET current_value = N'' WHERE name like N'Utility%'
UPDATE [dbo].[sysutility_ucp_configuration_internal] SET current_value = N'' WHERE name = N'MdwDatabaseName'
END
GO
/**********************************************************************/
/* Delete Managed Instance. */
/* */
/* */
/**********************************************************************/
IF OBJECT_ID ('dbo.sp_sysutility_ucp_remove_mi') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_ucp_remove_mi]', 0, 1) WITH NOWAIT;
DROP PROCEDURE dbo.sp_sysutility_ucp_remove_mi
END;
GO
RAISERROR ('Creating procedure [dbo].[sp_sysutility_ucp_remove_mi]', 0, 1) WITH NOWAIT;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_ucp_remove_mi]
@instance_id int
WITH EXECUTE AS OWNER
AS
BEGIN
DECLARE @retval INT
IF (@instance_id IS NULL)
BEGIN
RAISERROR(14043, -1, -1, 'instance_id', 'sp_sysutility_ucp_remove_mi')
RETURN(1)
END
DECLARE @instance_name SYSNAME
SELECT @instance_name = instance_name
FROM msdb.dbo.sysutility_ucp_managed_instances_internal
WHERE instance_id = @instance_id
-- Clean up managed instance health states and update dashboard stats
-- This block comes before the delete from sysutility_ucp_managed_instances_internal
-- so we can retrieve the instance name in case there's an error inside the block and
-- this sp is rerun
IF EXISTS (SELECT 1 FROM msdb.dbo.sysutility_ucp_mi_health_internal WHERE mi_name = @instance_name)
BEGIN
DECLARE @health_state_id INT
SELECT @health_state_id = latest_health_state_id FROM msdb.dbo.sysutility_ucp_processing_state_internal
-- Delete the managed instance record
DELETE FROM msdb.dbo.sysutility_ucp_mi_health_internal WHERE mi_name = @instance_name
-- Re-compute the dashboard health stats
DELETE FROM msdb.dbo.sysutility_ucp_aggregated_mi_health_internal WHERE set_number = @health_state_id
EXEC msdb.dbo.sp_sysutility_ucp_calculate_aggregated_mi_health @health_state_id
-- Delete the health records of DACs in the removed instance.
DELETE FROM msdb.dbo.sysutility_ucp_dac_health_internal WHERE dac_server_instance_name = @instance_name
-- Re-compute the DAC health stats in the dashboard
DELETE FROM msdb.dbo.sysutility_ucp_aggregated_dac_health_internal WHERE set_number = @health_state_id
EXEC msdb.dbo.sp_sysutility_ucp_calculate_aggregated_dac_health @health_state_id
END
DELETE [dbo].[sysutility_ucp_managed_instances_internal]
WHERE instance_id = @instance_id
SELECT @retval = @@error
RETURN(@retval)
END
GO
/**********************************************************************/
/* */
/* Remove a managed instance from its UCP */
/* */
/**********************************************************************/
IF OBJECT_ID ('dbo.sp_sysutility_mi_remove') IS NOT NULL
BEGIN
RAISERROR ('Dropping procedure [dbo].[sp_sysutility_mi_remove]', 0, 1) WITH NOWAIT;
DROP PROCEDURE [dbo].[sp_sysutility_mi_remove]
END;
GO
CREATE PROCEDURE [dbo].[sp_sysutility_mi_remove]
WITH EXECUTE AS OWNER
AS
BEGIN
SET NOCOUNT ON;
EXEC msdb.dbo.sp_sysutility_mi_disable_collection;
--###FP 1
EXEC msdb.dbo.sp_syscollector_disable_collector;
--###FP 2
DECLARE @collection_set_id int;
DECLARE @proxy_id int;
DECLARE @utility_collection_set_uid uniqueidentifier = N'ABA37A22-8039-48C6-8F8F-39BFE0A195DF';
-- find our collection set and determine if its proxy is set
SELECT
@collection_set_id = collection_set.collection_set_id
,@proxy_id = collection_set.proxy_id
FROM msdb.dbo.syscollector_collection_sets AS collection_set
WHERE collection_set.collection_set_uid = @utility_collection_set_uid;
-- determine if DC is running
-- if agent is not running, is_running won't be changed
-- so default it to false
DECLARE @is_running int = 0
EXEC msdb.dbo.sp_syscollector_get_collection_set_execution_status @collection_set_id, @is_running OUTPUT;
--###FP 3
IF (@is_running = 1)
BEGIN
EXEC msdb.dbo.sp_syscollector_stop_collection_set @collection_set_id;
END
--###FP 4
IF (@proxy_id IS NOT NULL )
BEGIN
-- retrieve the current cache directory setting
-- if the setting can't be found, assume it is not set
DECLARE @cache_directory_is_set bit = 0
SELECT @cache_directory_is_set = CASE WHEN config.parameter_value IS NULL THEN 0 ELSE 1 END
FROM msdb.dbo.syscollector_config_store AS config
WHERE config.parameter_name = N'CacheDirectory';
IF(@cache_directory_is_set = 1)
BEGIN
EXEC msdb.dbo.sp_syscollector_set_cache_directory @cache_directory = NULL;
END
--###FP 5
-- clear the proxy
-- because we only enter this block if proxy is set,
-- postpone clearing proxy until the end of the block
-- to ensure that if clearing the cache directory fails
-- we will re-enter this block the next time this proc is called
EXEC msdb.dbo.sp_syscollector_update_collection_set @collection_set_id = @collection_set_id, @proxy_name = N'';
--###FP 6
END
EXEC msdb.dbo.sp_syscollector_enable_collector;
--###FP 7
EXEC msdb.dbo.sp_sysutility_mi_remove_ucp_registration;
END;
GO
/**********************************************************************/
/* Provision security for utility objects */
/**********************************************************************/
EXEC sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_mi_file_space_health_internal', N'UtilityCMRReader'
EXEC sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_mi_database_health_internal', N'UtilityCMRReader'
EXEC sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_dac_file_space_health_internal', N'UtilityCMRReader'
EXEC sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_mi_volume_space_health_internal', N'UtilityCMRReader'
EXEC sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_mi_file_space_health', N'UtilityCMRReader'
EXEC sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_mi_database_health', N'UtilityCMRReader'
EXEC sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_dac_database_file_space_health', N'UtilityCMRReader'
EXEC sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_mi_volume_space_health', N'UtilityCMRReader'
/**********************************************************************/
/* Add an extended database property to identify database as a utility */
/* store. */
/* */
/**********************************************************************/
DECLARE @prop_name sysname
DECLARE @new_value sql_variant
DECLARE @old_value sql_variant
DECLARE @new_value_str varchar(256);
SET @prop_name = 'Microsoft_Management_Utility_Version'
SET @new_value = '___SQLVERSION___NEW___' -- This should be replaced at build time with the sql build number. See DC's code for how to do this when needed.
SELECT @old_value = value
FROM fn_listextendedproperty(@prop_name, NULL, NULL, NULL, NULL, NULL, NULL)
IF (@old_value IS NOT NULL)
BEGIN
-- At some point we might want to do version checking here, but for now, just drop the property
RAISERROR ('Dropping extended database property - Microsoft_Management_Utility_Version', 0, 1) WITH NOWAIT;
EXEC sp_dropextendedproperty @name = @prop_name
END
SET @new_value_str = CONVERT (varchar(256), @new_value);
RAISERROR ('Creating extended database property - Microsoft_Management_Utility_Version (version ''%s'')', 0, 1, @new_value_str) WITH NOWAIT;
EXEC sp_addextendedproperty
@name = @prop_name,
@value = @new_value
GO
-----------------------------------------------------------
-- Security for Utility objects
-----------------------------------------------------------
-- Provision the Utility tables: Grant the tables, Select permissions to public
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_mi_configuration_internal', N'UtilityIMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_mi_session_statistics_internal', N'UtilityIMRReader'
GRANT INSERT, DELETE ON [dbo].[sysutility_mi_session_statistics_internal] TO [UtilityIMRWriter]
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_mi_dac_execution_statistics_internal', N'UtilityIMRReader'
GRANT INSERT, DELETE ON [dbo].[sysutility_mi_dac_execution_statistics_internal] TO [UtilityIMRWriter]
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_mi_volumes_stage_internal', N'UtilityIMRReader'
GRANT INSERT, DELETE ON [dbo].[sysutility_mi_volumes_stage_internal] TO [UtilityIMRWriter]
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_mi_cpu_stage_internal', N'UtilityIMRReader'
GRANT INSERT, DELETE ON [dbo].[sysutility_mi_cpu_stage_internal] TO [UtilityIMRWriter]
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_mi_smo_stage_internal', N'UtilityIMRReader'
GRANT INSERT, DELETE ON [dbo].[sysutility_mi_smo_stage_internal] TO [UtilityIMRWriter]
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_mi_smo_properties_to_collect_internal', N'UtilityIMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_mi_smo_objects_to_collect_internal', N'UtilityIMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_managed_instances_internal', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_configuration_internal', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_processing_state_internal', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_health_policies_internal', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_aggregated_dac_health_internal', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_aggregated_mi_health_internal', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_dac_health_internal', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_mi_health_internal', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_policy_check_conditions_internal', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_policy_target_conditions_internal', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_deployed_dacs', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_computers', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_volumes', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_utility_space_utilization', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_instances', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_databases', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_filegroups', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_datafiles', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_logfiles', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_mi_database_file_space_utilizations', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_dac_database_file_space_utilizations', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_mi_volume_space_utilizations', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_dac_volume_space_utilizations', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_mi_cpu_utilizations', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_ucp_get_file_space_utilization_history', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_ucp_get_cpu_utilization_history', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_get_is_instance_ucp', N'UtilityCMRReader'
GO
-- Provision the Utility views: Keep the views UtilityCMRReader
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_managed_instances', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_configuration', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_policies', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_policy_violations', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_aggregated_dac_health', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_aggregated_mi_health', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_dac_health', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_mi_health', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_policy_check_conditions', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_policy_target_conditions', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_dac_policy_type', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_instance_policy_type', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_instance_policies', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_dac_policies', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sysutility_ucp_computer_policies', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_encode_sqlname_for_powershell', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_ucp_get_applicable_policy', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_ucp_get_aggregated_failure_count', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_ucp_get_global_health_policy', N'UtilityCMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_ucp_get_aggregated_health', N'UtilityCMRReader'
GO
-- Grant Utility SPs, execute permissions to the role
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sp_sysutility_mi_collect_dac_execution_statistics_internal', N'UtilityIMRWriter'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'sp_sysutility_mi_get_dac_execution_statistics_internal', N'UtilityIMRWriter'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_mi_get_batch_manifest', N'UtilityIMRWriter'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_mi_get_cpu_architecture_name', N'UtilityIMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_mi_get_cpu_family_name', N'UtilityIMRReader'
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_get_culture_invariant_conversion_style_internal', N'UtilityIMRReader'
GO
-- Provision the table valued functions
EXEC dbo.sp_sysutility_ucp_provision_utility_object_internal N'fn_sysutility_ucp_get_policy_violations', N'UtilityCMRReader'
GO
-- Redirect the Utility msdb wrapper views from the msdb stub tables to the sysutility_mdw tables, if this
-- instance is a UCP. We tell the proc not to refresh the msdb views (yet), though. Because setup upgrades
-- the sysutility_mdw database after msdb, when this script is executed the MDW tables might not yet have all
-- of the columns that are required by the upgraded msdb views. Refeshing them in this partially-upgraded
-- state would cause an error. This procedure will be executed again after instmdw.sql has been run and
-- both MDW and msdb have been upgraded. At that time, the views will be refreshed.
EXEC msdb.dbo.sp_sysutility_ucp_initialize_mdw
@mdw_database_name = 'sysutility_mdw',
@require_mdw = 0,
@refresh_views = 0;
GO
DECLARE @advanced_options_original_value INT;
DECLARE @configuration_original_value INT;
SELECT
@advanced_options_original_value = advanced_options_original_value,
@configuration_original_value = configuration_original_value
FROM #configuration_original_values
WHERE configuration_option = 'Agent XPs';
-- Restore Agent XPs to previous state
EXECUTE #sp_restore_component_state 'Agent XPs',
@advopt_old_value = @advanced_options_original_value,
@comp_old_value = @configuration_original_value;
GO
/**************************************************************/
/* END UTILITY SCRIPTS */
/**************************************************************/
/**********************************************************************/
/* OBD.SQL */
/* */
/* Signs all the SPs that will be added to the */
/* Off By Default component. */
/* TODO: Split this too based on each component. */
/* */
/* */
/* Copyright (c) Microsoft Corporation */
/* All Rights Reserved. */
/* */
/**********************************************************************/
/**************************************************************/
/* Sign agent sps and add them to Off By Default component */
/* */
/* Also sign SPs for other components located in MSDB */
/**************************************************************/
-- List all of the stored procedures we need to sign with the Agent
-- signing certicate. Optionally if your SP belongs in the 'Agent XPs'
-- Off-by-default component, then specify 1 for the 'obdComponent'
-- column; If it belongs in 'DBMail XPs', specify 2.
create table #sp_table (name sysname, sign int, obdComponent int, bNewProc int)
go
insert into #sp_table values(N'sp_sqlagent_is_srvrolemember', 1, 0, 0)
insert into #sp_table values(N'sp_verify_category_identifiers', 1, 0, 0)
insert into #sp_table values(N'sp_verify_proxy_identifiers', 1, 0, 0)
insert into #sp_table values(N'sp_verify_credential_identifiers', 1, 0, 0)
insert into #sp_table values(N'sp_verify_subsystem_identifiers', 1, 0, 0)
insert into #sp_table values(N'sp_verify_login_identifiers', 1, 0, 0)
insert into #sp_table values(N'sp_verify_proxy', 1, 0, 0)
insert into #sp_table values(N'sp_add_proxy', 1, 0, 0)
insert into #sp_table values(N'sp_delete_proxy', 1, 0, 0)
insert into #sp_table values(N'sp_update_proxy', 1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_is_member', 1, 0, 0)
insert into #sp_table values(N'sp_verify_proxy_permissions', 1, 0, 0)
insert into #sp_table values(N'sp_help_proxy', 1, 0, 0)
insert into #sp_table values(N'sp_grant_proxy_to_subsystem', 1, 0, 0)
insert into #sp_table values(N'sp_grant_login_to_proxy', 1, 0, 0)
insert into #sp_table values(N'sp_revoke_login_from_proxy', 1, 0, 0)
insert into #sp_table values(N'sp_revoke_proxy_from_subsystem', 1, 0, 0)
insert into #sp_table values(N'sp_enum_proxy_for_subsystem', 1, 0, 0)
insert into #sp_table values(N'sp_enum_login_for_proxy', 1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_get_startup_info', 1, 1, 0)
insert into #sp_table values(N'sp_sqlagent_has_server_access', 1, 1, 0)
insert into #sp_table values(N'sp_sem_add_message', 1, 0, 0)
insert into #sp_table values(N'sp_sem_drop_message', 1, 0, 0)
insert into #sp_table values(N'sp_get_message_description', 1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_get_perf_counters', 1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_notify', 1, 1, 0)
insert into #sp_table values(N'sp_is_sqlagent_starting', 1, 1, 0)
insert into #sp_table values(N'sp_verify_job_identifiers', 1, 0, 0)
insert into #sp_table values(N'sp_verify_schedule_identifiers', 1, 0, 0)
insert into #sp_table values(N'sp_verify_jobproc_caller', 1, 0, 0)
insert into #sp_table values(N'sp_downloaded_row_limiter', 1, 1, 0)
insert into #sp_table values(N'sp_post_msx_operation', 1, 1, 0)
insert into #sp_table values(N'sp_verify_performance_condition', 1, 0, 0)
insert into #sp_table values(N'sp_verify_job_date', 1, 0, 0)
insert into #sp_table values(N'sp_verify_job_time', 1, 0, 0)
insert into #sp_table values(N'sp_verify_alert', 1, 1, 0)
insert into #sp_table values(N'sp_update_alert', 1, 0, 0)
insert into #sp_table values(N'sp_delete_job_references', 1, 0, 0)
insert into #sp_table values(N'sp_delete_all_msx_jobs', 1, 0, 0)
insert into #sp_table values(N'sp_generate_target_server_job_assignment_sql', 1, 0, 0)
insert into #sp_table values(N'sp_generate_server_description', 1, 1, 0)
insert into #sp_table values(N'sp_msx_set_account', 1, 1, 0)
insert into #sp_table values(N'sp_msx_get_account', 1, 1, 0)
insert into #sp_table values(N'sp_delete_operator', 1, 0, 0)
insert into #sp_table values(N'sp_msx_defect', 1, 1, 0)
insert into #sp_table values(N'sp_msx_enlist', 1, 1, 0)
insert into #sp_table values(N'sp_delete_targetserver', 1, 0, 0)
insert into #sp_table values(N'sp_get_sqlagent_properties', 1, 1, 0)
insert into #sp_table values(N'sp_set_sqlagent_properties', 1, 1, 0)
insert into #sp_table values(N'sp_add_targetservergroup', 1, 0, 0)
insert into #sp_table values(N'sp_update_targetservergroup', 1, 0, 0)
insert into #sp_table values(N'sp_delete_targetservergroup', 1, 0, 0)
insert into #sp_table values(N'sp_help_targetservergroup', 1, 0, 0)
insert into #sp_table values(N'sp_add_targetsvrgrp_member', 1, 0, 0)
insert into #sp_table values(N'sp_delete_targetsvrgrp_member', 1, 0, 0)
insert into #sp_table values(N'sp_verify_category', 1, 0, 0)
insert into #sp_table values(N'sp_add_category', 1, 0, 0)
insert into #sp_table values(N'sp_update_category', 1, 0, 0)
insert into #sp_table values(N'sp_delete_category', 1, 0, 0)
insert into #sp_table values(N'sp_help_category', 1, 0, 0)
insert into #sp_table values(N'sp_help_targetserver', 1, 0, 0)
insert into #sp_table values(N'sp_resync_targetserver', 1, 0, 0)
insert into #sp_table values(N'sp_purge_jobhistory', 1, 0, 0)
insert into #sp_table values(N'sp_help_jobhistory', 1, 0, 0)
insert into #sp_table values(N'sp_help_jobhistory_full', 1, 0, 0)
insert into #sp_table values(N'sp_help_jobhistory_summary', 1, 0, 0)
insert into #sp_table values(N'sp_help_jobhistory_sem', 1, 0, 0)
insert into #sp_table values(N'sp_add_jobserver', 1, 0, 0)
insert into #sp_table values(N'sp_delete_jobserver', 1, 0, 0)
insert into #sp_table values(N'sp_help_jobserver', 1, 0, 0)
insert into #sp_table values(N'sp_help_downloadlist', 1, 0, 0)
insert into #sp_table values(N'sp_enum_sqlagent_subsystems', 1, 0, 0)
insert into #sp_table values(N'sp_enum_sqlagent_subsystems_internal', 1, 0, 0)
insert into #sp_table values(N'sp_verify_subsystem', 1, 1, 0)
insert into #sp_table values(N'sp_verify_subsystems', 1, 0, 0)
insert into #sp_table values(N'sp_verify_schedule', 1, 0, 0)
insert into #sp_table values(N'sp_add_schedule', 1, 0, 0)
insert into #sp_table values(N'sp_attach_schedule', 1, 0, 0)
insert into #sp_table values(N'sp_detach_schedule', 1, 0, 0)
insert into #sp_table values(N'sp_update_schedule', 1, 0, 0)
insert into #sp_table values(N'sp_delete_schedule', 1, 0, 0)
insert into #sp_table values(N'sp_get_jobstep_db_username', 1, 0, 0)
insert into #sp_table values(N'sp_verify_jobstep', 1, 0, 0)
insert into #sp_table values(N'sp_add_jobstep_internal', 1, 0, 0)
insert into #sp_table values(N'sp_add_jobstep', 1, 0, 0)
insert into #sp_table values(N'sp_update_jobstep', 1, 0, 0)
insert into #sp_table values(N'sp_delete_jobstep', 1, 0, 0)
insert into #sp_table values(N'sp_help_jobstep', 1, 0, 0)
insert into #sp_table values(N'sp_write_sysjobstep_log', 1, 0, 0)
insert into #sp_table values(N'sp_help_jobsteplog', 1, 0, 0)
insert into #sp_table values(N'sp_delete_jobsteplog', 1, 0, 0)
insert into #sp_table values(N'sp_get_schedule_description', 1, 1, 0)
insert into #sp_table values(N'sp_add_jobschedule', 1, 0, 0)
insert into #sp_table values(N'sp_update_replication_job_parameter', 1, 0, 0)
insert into #sp_table values(N'sp_update_jobschedule', 1, 0, 0)
insert into #sp_table values(N'sp_delete_jobschedule', 1, 0, 0)
insert into #sp_table values(N'sp_help_schedule', 1, 0, 0)
insert into #sp_table values(N'sp_help_jobschedule', 1, 0, 0)
insert into #sp_table values(N'sp_verify_job', 1, 1, 0)
insert into #sp_table values(N'sp_add_job', 1, 0, 0)
insert into #sp_table values(N'sp_update_job', 1, 0, 0)
insert into #sp_table values(N'sp_delete_job', 1, 0, 0)
insert into #sp_table values(N'sp_get_composite_job_info', 1, 1, 0)
insert into #sp_table values(N'sp_help_job', 1, 0, 0)
insert into #sp_table values(N'sp_help_jobcount ', 1, 0, 0)
insert into #sp_table values(N'sp_help_jobs_in_schedule', 1, 0, 0)
insert into #sp_table values(N'sp_manage_jobs_by_login', 1, 0, 0)
insert into #sp_table values(N'sp_apply_job_to_targets', 1, 0, 0)
insert into #sp_table values(N'sp_remove_job_from_targets', 1, 0, 0)
insert into #sp_table values(N'sp_get_job_alerts', 1, 0, 0)
insert into #sp_table values(N'sp_convert_jobid_to_char', 1, 0, 0)
insert into #sp_table values(N'sp_start_job', 1, 0, 0)
insert into #sp_table values(N'sp_stop_job', 1, 0, 0)
insert into #sp_table values(N'sp_cycle_agent_errorlog', 1, 0, 0)
insert into #sp_table values(N'sp_get_chunked_jobstep_params', 1, 0, 0)
insert into #sp_table values(N'sp_check_for_owned_jobs', 1, 0, 0)
insert into #sp_table values(N'sp_check_for_owned_jobsteps', 1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_refresh_job', 1, 0, 0)
insert into #sp_table values(N'sp_jobhistory_row_limiter', 1, 1, 0)
insert into #sp_table values(N'sp_sqlagent_log_jobhistory', 1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_check_msx_version', 1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_probe_msx', 1, 0, 0)
insert into #sp_table values(N'sp_set_local_time', 1, 1, 0)
insert into #sp_table values(N'sp_multi_server_job_summary', 1, 0, 0)
insert into #sp_table values(N'sp_target_server_summary', 1, 0, 0)
insert into #sp_table values(N'sp_uniquetaskname', 1, 0, 0)
insert into #sp_table values(N'sp_addtask', 1, 0, 0)
insert into #sp_table values(N'sp_droptask', 1, 0, 0)
insert into #sp_table values(N'sp_add_alert_internal', 1, 0, 0)
insert into #sp_table values(N'sp_add_alert', 1, 0, 0)
insert into #sp_table values(N'sp_delete_alert', 1, 0, 0)
insert into #sp_table values(N'sp_help_alert', 1, 0, 0)
insert into #sp_table values(N'sp_verify_operator', 1, 0, 0)
insert into #sp_table values(N'sp_add_operator', 1, 0, 0)
insert into #sp_table values(N'sp_update_operator', 1, 1, 0)
insert into #sp_table values(N'sp_help_operator', 1, 0, 0)
insert into #sp_table values(N'sp_help_operator_jobs', 1, 0, 0)
insert into #sp_table values(N'sp_verify_operator_identifiers', 1, 0, 0)
insert into #sp_table values(N'sp_notify_operator', 1, 0, 0)
insert into #sp_table values(N'sp_verify_notification', 1, 0, 0)
insert into #sp_table values(N'sp_add_notification', 1, 0, 0)
insert into #sp_table values(N'sp_update_notification', 1, 0, 0)
insert into #sp_table values(N'sp_delete_notification', 1, 0, 0)
insert into #sp_table values(N'sp_help_notification', 1, 0, 0)
insert into #sp_table values(N'sp_help_jobactivity', 1, 0, 0)
insert into #sp_table values(N'sp_enlist_tsx', 1, 1, 0)
insert into #sp_table values(N'trig_targetserver_insert', 1, 0, 0)
-- Database Mail configuration procs
insert into #sp_table values(N'sysmail_verify_accountparams_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_verify_principal_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_verify_profile_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_verify_account_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_add_profile_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_update_profile_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_delete_profile_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_help_profile_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_create_user_credential_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_alter_user_credential_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_drop_user_credential_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_add_account_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_update_account_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_delete_account_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_help_account_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_help_admin_account_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_add_profileaccount_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_update_profileaccount_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_delete_profileaccount_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_help_profileaccount_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_configure_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_help_configure_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_help_configure_value_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_add_principalprofile_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_update_principalprofile_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_delete_principalprofile_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_help_principalprofile_sp', 1, 0, 0)
-- Database Mail: mail host database specific procs
insert into #sp_table values(N'sysmail_start_sp', 1, 2, 0)
insert into #sp_table values(N'sysmail_stop_sp', 1, 2, 0)
insert into #sp_table values(N'sysmail_logmailevent_sp', 1, 0, 0)
insert into #sp_table values(N'sp_SendMailMessage', 1, 0, 0)
insert into #sp_table values(N'sp_isprohibited', 1, 0, 0)
insert into #sp_table values(N'sp_SendMailQueues', 1, 0, 0)
insert into #sp_table values(N'sp_ProcessResponse', 1, 0, 0)
insert into #sp_table values(N'sp_MailItemResultSets', 1, 0, 0)
insert into #sp_table values(N'sp_process_DialogTimer', 1, 0, 0)
insert into #sp_table values(N'sp_readrequest', 1, 0, 0)
insert into #sp_table values(N'sp_GetAttachmentData', 1, 0, 0)
insert into #sp_table values(N'sp_RunMailQuery', 1, 0, 0)
insert into #sp_table values(N'sysmail_help_queue_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_help_status_sp', 1, 2, 0)
insert into #sp_table values(N'sysmail_delete_mailitems_sp', 1, 0, 0)
insert into #sp_table values(N'sysmail_delete_log_sp', 1, 0, 0)
insert into #sp_table values(N'sp_validate_user', 1, 2, 0)
insert into #sp_table values(N'sp_send_dbmail', 1, 2, 0)
insert into #sp_table values(N'sp_ExternalMailQueueListener', 1, 0, 0)
insert into #sp_table values(N'sp_sysmail_activate', 1, 0, 0)
insert into #sp_table values(N'sp_get_script', 1, 0, 0)
-- Maintenance Plans
insert into #sp_table values(N'sp_maintplan_delete_log', 1, 0, 0)
insert into #sp_table values(N'sp_maintplan_delete_subplan', 1, 0, 0)
insert into #sp_table values(N'sp_maintplan_open_logentry', 1, 0, 0)
insert into #sp_table values(N'sp_maintplan_close_logentry', 1, 0, 0)
insert into #sp_table values(N'sp_maintplan_update_log', 1, 0, 0)
insert into #sp_table values(N'sp_maintplan_update_subplan', 1, 0, 0)
insert into #sp_table values(N'sp_maintplan_delete_plan', 1, 0, 0)
insert into #sp_table values(N'sp_maintplan_start', 1, 0, 0)
insert into #sp_table values(N'sp_clear_dbmaintplan_by_db', 1, 0, 0)
insert into #sp_table values(N'sp_add_maintenance_plan', 1, 0, 0)
insert into #sp_table values(N'sp_delete_maintenance_plan', 1, 0, 0)
insert into #sp_table values(N'sp_add_maintenance_plan_db', 1, 0, 0)
insert into #sp_table values(N'sp_delete_maintenance_plan_db', 1, 0, 0)
insert into #sp_table values(N'sp_add_maintenance_plan_job', 1, 1, 0)
insert into #sp_table values(N'sp_delete_maintenance_plan_job', 1, 0, 0)
insert into #sp_table values(N'sp_help_maintenance_plan', 1, 0, 0)
insert into #sp_table values(N'sp_maintplan_update_subplan_tsx', 1, 0, 0)
insert into #sp_table values(N'sp_maintplan_subplans_by_job', 1, 0, 0)
-- Log Shipping
insert into #sp_table values(N'sp_add_log_shipping_monitor_jobs', 1, 0, 0)
insert into #sp_table values(N'sp_add_log_shipping_primary', 1, 0, 0)
insert into #sp_table values(N'sp_add_log_shipping_secondary', 1, 0, 0)
insert into #sp_table values(N'sp_delete_log_shipping_monitor_jobs', 1, 0, 0)
insert into #sp_table values(N'sp_delete_log_shipping_primary', 1, 0, 0)
insert into #sp_table values(N'sp_delete_log_shipping_secondary ', 1, 0, 0)
insert into #sp_table values(N'sp_log_shipping_in_sync', 1, 0, 0)
insert into #sp_table values(N'sp_log_shipping_get_date_from_file ', 1, 0, 0)
insert into #sp_table values(N'sp_get_log_shipping_monitor_info', 1, 0, 0)
insert into #sp_table values(N'sp_update_log_shipping_monitor_info', 1, 0, 0)
insert into #sp_table values(N'sp_delete_log_shipping_monitor_info', 1, 0, 0)
insert into #sp_table values(N'sp_remove_log_shipping_monitor_account', 1, 0, 0)
insert into #sp_table values(N'sp_log_shipping_monitor_backup', 1, 0, 0)
insert into #sp_table values(N'sp_log_shipping_monitor_restore', 1, 0, 0)
insert into #sp_table values(N'sp_change_monitor_role', 1, 0, 0)
insert into #sp_table values(N'sp_create_log_shipping_monitor_account', 1, 0, 0)
-- SSIS
insert into #sp_table values(N'sp_ssis_addlogentry', 1, 0, 0)
insert into #sp_table values(N'sp_ssis_listpackages', 1, 0, 0)
insert into #sp_table values(N'sp_ssis_listfolders', 1, 0, 0)
insert into #sp_table values(N'sp_ssis_deletepackage', 1, 0, 0)
insert into #sp_table values(N'sp_ssis_deletefolder', 1, 0, 0)
insert into #sp_table values(N'sp_ssis_getpackage', 1, 0, 0)
insert into #sp_table values(N'sp_ssis_getfolder', 1, 0, 0)
insert into #sp_table values(N'sp_ssis_putpackage', 1, 0, 0)
insert into #sp_table values(N'sp_ssis_addfolder', 1, 0, 0)
insert into #sp_table values(N'sp_ssis_renamefolder', 1, 0, 0)
insert into #sp_table values(N'sp_ssis_setpackageroles', 1, 0, 0)
insert into #sp_table values(N'sp_ssis_getpackageroles', 1, 0, 0)
go
/**************************************************************/
/* Alwayson built-in policies */
/**************************************************************/
SET NOCOUNT ON
PRINT ''
PRINT '--------------------------------'
PRINT 'Starting execution of Alwayson.SQL'
PRINT '--------------------------------'
go
-------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create temp procedure to handle the cascade delete issue in procedure sp_syspolicy_delete_policy, see VSTS 904601 for more details.
--- basically this procedure is to simulate the sp_syspolicy_delete_policy + syspolicy_instead_delete_policy_trigger, so if there is any logic change
--- there, we need to update this temp proc too.
-------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE PROCEDURE #sp_syspolicy_cascade_delete_policy
@name sysname = NULL
AS
BEGIN
DECLARE @policyid int;
DECLARE @retval int;
EXEC @retval = [msdb].[dbo].[sp_syspolicy_verify_policy_identifiers] @name, @policyid OUTPUT
IF (@retval = 0)
BEGIN
DELETE msdb.dbo.syspolicy_policy_execution_history_internal WHERE policy_id = @policyid
DELETE msdb.dbo.syspolicy_system_health_state_internal WHERE policy_id = @policyid
EXEC msdb.dbo.sp_syspolicy_delete_policy @policy_id = @policyid
END
END
go
Begin
Declare @alwayson_target_set_id int
Declare @alwayson_policy_helptext NVARCHAR(1024)
Declare @alwayson_policy_description NVARCHAR(max)
Declare @condition_name NVARCHAR(1024)
Declare @expression NVARCHAR(max)
Declare @alwayson_policy_helptext_prefix NVARCHAR(100)
Declare @alwayson_policy_description_prefix NVARCHAR(100)
select @alwayson_policy_helptext_prefix = 'Alwayson Policy Helptext ID:'
select @alwayson_policy_description_prefix = 'Alwayson Policy Description ID:'
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Delete existing Policies,objectSets
-- NOTE:
-- We shall not delete condition and category because customer may have dependency on condition, especially on category.
-- so if we delete the category, the upgrade will be broken.
-- instead we shall use add_condition/add_category if the condition/category does not exist.
-- if they exist, use update.
-- For Denali, the updating category does not really do anything. But for the future if we want to change the category name, that will be useful
-- the condition update will be very useful if we decide to change the expression of the condition.
-- the policy does not have any dependency, so "delete and add" are fine.
-- object set is also fine because it's already referred by our policy, user-defined policy can not refer to it.
--
-- one thing here is if we upgrade from Denali CTP3 (SSS) to Denali CTP3 refresh (MS) or later, the old policy/condition/category will be left
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Deleting existing policies, objectsets...'
PRINT ''
PRINT 'Deleting AlwaysOnArJoinStateHealthPolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnArJoinStateHealthPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnArJoinStateHealthPolicy', @marker=0
EXECUTE #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnArJoinStateHealthPolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnArJoinStateHealthPolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnArJoinStateHealthPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnArJoinStateHealthPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnArJoinStateHealthPolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgReplicasConnectionHealthPolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnAgReplicasConnectionHealthPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgReplicasConnectionHealthPolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnAgReplicasConnectionHealthPolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgReplicasConnectionHealthPolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnAgReplicasConnectionHealthPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgReplicasConnectionHealthPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnAgReplicasConnectionHealthPolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgReplicasDataSynchronizationHealthPolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgReplicasDataSynchronizationHealthPolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgReplicasRoleHealthPolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnAgReplicasRoleHealthPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgReplicasRoleHealthPolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnAgReplicasRoleHealthPolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgReplicasRoleHealthPolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnAgReplicasRoleHealthPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgReplicasRoleHealthPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnAgReplicasRoleHealthPolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnDbrJoinStatePolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnDbrJoinStatePolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnDbrJoinStatePolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnDbrJoinStatePolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnDbrJoinStatePolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnDbrJoinStatePolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnDbrJoinStatePolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnDbrJoinStatePolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnDbrSuspendStatePolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnDbrSuspendStatePolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnDbrSuspendStatePolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnDbrSuspendStatePolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnDbrSuspendStatePolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnDbrSuspendStatePolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnDbrSuspendStatePolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnDbrSuspendStatePolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgOnlineStateHealthPolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnAgOnlineStateHealthPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgOnlineStateHealthPolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnAgOnlineStateHealthPolicy'
END
PRINT ''
PRINT 'Deleting existing AlwaysOnAgOnlineStateHealthPolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnAgOnlineStateHealthPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgOnlineStateHealthPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnAgOnlineStateHealthPolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgAutomaticFailoverHealthPolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnAgAutomaticFailoverHealthPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgAutomaticFailoverHealthPolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnAgAutomaticFailoverHealthPolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgAutomaticFailoverHealthPolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnAgAutomaticFailoverHealthPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgAutomaticFailoverHealthPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnAgAutomaticFailoverHealthPolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnArConnectionHealthPolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnArConnectionHealthPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnArConnectionHealthPolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnArConnectionHealthPolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnArConnectionHealthPolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnArConnectionHealthPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnArConnectionHealthPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnArConnectionHealthPolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnDbrDataSynchronizationState'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnDbrDataSynchronizationState')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnDbrDataSynchronizationState', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnDbrDataSynchronizationState'
END
PRINT ''
PRINT 'Deleting AlwaysOnDbrDataSynchronizationState_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnDbrDataSynchronizationState_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnDbrDataSynchronizationState_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnDbrDataSynchronizationState_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnArDataSynchronizationHealthPolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnArDataSynchronizationHealthPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnArDataSynchronizationHealthPolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnArDataSynchronizationHealthPolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnArDataSynchronizationHealthPolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnArDataSynchronizationHealthPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnArDataSynchronizationHealthPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnArDataSynchronizationHealthPolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnArRoleHealthPolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnArRoleHealthPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnArRoleHealthPolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnArRoleHealthPolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnArRoleHealthPolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnArRoleHealthPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnArRoleHealthPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnArRoleHealthPolicy_ObjectSet'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgWSFClusterHealthPolicy'
IF EXISTS(SELECT policy_id FROM msdb.dbo.syspolicy_policies WHERE name=N'AlwaysOnAgWSFClusterHealthPolicy')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgWSFClusterHealthPolicy', @marker=0
EXEC #sp_syspolicy_cascade_delete_policy @name=N'AlwaysOnAgWSFClusterHealthPolicy'
END
PRINT ''
PRINT 'Deleting AlwaysOnAgWSFClusterHealthPolicy_ObjectSet'
IF EXISTS(SELECT object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name=N'AlwaysOnAgWSFClusterHealthPolicy_ObjectSet')
BEGIN
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgWSFClusterHealthPolicy_ObjectSet', @marker=0
EXEC msdb.dbo.sp_syspolicy_delete_object_set @object_set_name=N'AlwaysOnAgWSFClusterHealthPolicy_ObjectSet'
END
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Category: Availability group errors (any replica role)
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating category: Availability group errors (any replica role)...'
IF EXISTS(SELECT policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name=N'Availability group errors (any replica role)')
BEGIN
EXEC msdb.dbo.sp_syspolicy_rename_policy_category @name=N'Availability group errors (any replica role)', @new_name=N'Availability group errors (any replica role)'
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_policy_category @name=N'Availability group errors (any replica role)', @policy_category_id=0
END
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Category: Availability group errors (primary replica only)
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating category: Availability group errors (primary replica only)...'
IF EXISTS(SELECT policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name=N'Availability group errors (primary replica only)')
BEGIN
EXEC msdb.dbo.sp_syspolicy_rename_policy_category @name=N'Availability group errors (primary replica only)', @new_name=N'Availability group errors (primary replica only)'
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_policy_category @name=N'Availability group errors (primary replica only)', @policy_category_id=0
END
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Category: Availability replica errors
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating category: Availability replica errors...'
IF EXISTS(SELECT policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name=N'Availability replica errors')
BEGIN
EXEC msdb.dbo.sp_syspolicy_rename_policy_category @name=N'Availability replica errors', @new_name=N'Availability replica errors'
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_policy_category @name=N'Availability replica errors', @policy_category_id=0
END
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Category: Availability database errors
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating category: Availability database errors...'
IF EXISTS(SELECT policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name=N'Availability database errors')
BEGIN
EXEC msdb.dbo.sp_syspolicy_rename_policy_category @name=N'Availability database errors', @new_name=N'Availability database errors'
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_policy_category @name=N'Availability database errors', @policy_category_id=0
END
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Category: Availability group warnings (any replica role)
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating category: Availability group warnings (any replica role)...'
IF EXISTS(SELECT policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name=N'Availability group warnings (any replica role)')
BEGIN
EXEC msdb.dbo.sp_syspolicy_rename_policy_category @name=N'Availability group warnings (any replica role)', @new_name=N'Availability group warnings (any replica role)'
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_policy_category @name=N'Availability group warnings (any replica role)', @policy_category_id=0
END
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Category: Availability group warnings (primary replica only)
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating category: Availability group warnings (primary replica only)...'
IF EXISTS(SELECT policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name=N'Availability group warnings (primary replica only)')
BEGIN
EXEC msdb.dbo.sp_syspolicy_rename_policy_category @name=N'Availability group warnings (primary replica only)', @new_name=N'Availability group warnings (primary replica only)'
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_policy_category @name=N'Availability group warnings (primary replica only)', @policy_category_id=0
END
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Category: Availability replica warnings
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating category: Availability replica warnings...'
IF EXISTS(SELECT policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name=N'Availability replica warnings')
BEGIN
EXEC msdb.dbo.sp_syspolicy_rename_policy_category @name=N'Availability replica warnings', @new_name=N'Availability replica warnings'
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_policy_category @name=N'Availability replica warnings', @policy_category_id=0
END
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Category: Availability database warnings
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating category: Availability database warnings...'
IF EXISTS(SELECT policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name=N'Availability database warnings')
BEGIN
EXEC msdb.dbo.sp_syspolicy_rename_policy_category @name=N'Availability database warnings', @new_name=N'Availability database warnings'
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_policy_category @name=N'Availability database warnings', @policy_category_id=0
END
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnAgAutomaticFailoverHealthCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnAgAutomaticFailoverHealthCondition...'
set @condition_name = N'AlwaysOnAgAutomaticFailoverHealthCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>OR</OpType>
<Count>2</Count>
<Group>
<TypeClass>Bool</TypeClass>
<Count>1</Count>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>AND</OpType>
<Count>2</Count>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Bool</TypeClass>
<Name>IsAutoFailover</Name>
</Attribute>
<Function>
<TypeClass>Bool</TypeClass>
<FunctionType>True</FunctionType>
<ReturnType>Bool</ReturnType>
<Count>0</Count>
</Function>
</Operator>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>GT</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>NumberOfSynchronizedSecondaryReplicas</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>
</Operator>
</Group>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Bool</TypeClass>
<Name>IsAutoFailover</Name>
</Attribute>
<Function>
<TypeClass>Bool</TypeClass>
<FunctionType>False</FunctionType>
<ReturnType>Bool</ReturnType>
<Count>0</Count>
</Function>
</Operator>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnDbrJoinStateCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnDbrJoinStateCondition...'
set @condition_name = N'AlwaysOnDbrJoinStateCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Bool</TypeClass>
<Name>IsJoined</Name>
</Attribute>
<Function>
<TypeClass>Bool</TypeClass>
<FunctionType>True</FunctionType>
<ReturnType>Bool</ReturnType>
<Count>0</Count>
</Function>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'DatabaseReplicaState', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'DatabaseReplicaState', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnAgWSFClusterHealthCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnAgWSFClusterHealthCondition...'
set @condition_name = N'AlwaysOnAgWSFClusterHealthCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ClusterQuorumState</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.ClusterQuorumState</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>NormalQuorum</Value>
</Constant>
</Function>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'Server', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'Server', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnArConnectionHealthCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnArConnectionHealthCondition...'
set @condition_name = N'AlwaysOnArConnectionHealthCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ConnectionState</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.AvailabilityReplicaConnectionState</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Connected</Value>
</Constant>
</Function>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'AvailabilityReplica', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'AvailabilityReplica', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnAgReplicasConnectionHealthCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnAgReplicasConnectionHealthCondition...'
set @condition_name = N'AlwaysOnAgReplicasConnectionHealthCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>NumberOfDisconnectedReplicas</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnAgReplicasDataSynchronizationHealthCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnAgReplicasDataSynchronizationHealthCondition...'
set @condition_name = N'AlwaysOnAgReplicasDataSynchronizationHealthCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>NumberOfNotSynchronizingReplicas</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnAgReplicasRoleHealthCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnAgReplicasRoleHealthCondition...'
set @condition_name = N'AlwaysOnAgReplicasRoleHealthCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>NumberOfReplicasWithUnhealthyRole</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnAgSynchronousReplicasDataSynchronizationHealthCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnAgSynchronousReplicasDataSynchronizationHealthCondition...'
set @condition_name = N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>NumberOfNotSynchronizedReplicas</Name>
</Attribute>
<Constant>
<TypeClass>Numeric</TypeClass>
<ObjType>System.Double</ObjType>
<Value>0</Value>
</Constant>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnDbrSuspendStateCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnDbrSuspendStateCondition...'
set @condition_name = N'AlwaysOnDbrSuspendStateCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Bool</TypeClass>
<Name>IsSuspended</Name>
</Attribute>
<Function>
<TypeClass>Bool</TypeClass>
<FunctionType>False</FunctionType>
<ReturnType>Bool</ReturnType>
<Count>0</Count>
</Function>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'DatabaseReplicaState', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'DatabaseReplicaState', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnDbrDataSynchronizationCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnDbrDataSynchronizationCondition...'
set @condition_name = N'AlwaysOnDbrDataSynchronizationCondition'
set @expression = N'<Group>
<TypeClass>Bool</TypeClass>
<Count>1</Count>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>OR</OpType>
<Count>2</Count>
<Group>
<TypeClass>Bool</TypeClass>
<Count>1</Count>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>AND</OpType>
<Count>2</Count>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>ReplicaAvailabilityMode</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.AvailabilityReplicaAvailabilityMode</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>AsynchronousCommit</Value>
</Constant>
</Function>
</Operator>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>NE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>SynchronizationState</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.AvailabilityDatabaseSynchronizationState</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>NotSynchronizing</Value>
</Constant>
</Function>
</Operator>
</Operator>
</Group>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>SynchronizationState</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.AvailabilityDatabaseSynchronizationState</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Synchronized</Value>
</Constant>
</Function>
</Operator>
</Operator>
</Group>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'DatabaseReplicaState', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'DatabaseReplicaState', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1 -------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: IsHadrEnabled
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: IsHadrEnabled...'
set @condition_name = N'IsHadrEnabled'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Bool</TypeClass>
<Name>IsHadrEnabled</Name>
</Attribute>
<Function>
<TypeClass>Bool</TypeClass>
<FunctionType>True</FunctionType>
<ReturnType>Bool</ReturnType>
<Count>0</Count>
</Function>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'Server', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'Server', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnAgOnlineStateHealthCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnAgOnlineStateHealthCondition...'
set @condition_name = N'AlwaysOnAgOnlineStateHealthCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Bool</TypeClass>
<Name>IsOnline</Name>
</Attribute>
<Function>
<TypeClass>Bool</TypeClass>
<FunctionType>True</FunctionType>
<ReturnType>Bool</ReturnType>
<Count>0</Count>
</Function>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'IAvailabilityGroupState', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnArDataSynchronizationHealthCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnArDataSynchronizationHealthCondition...'
set @condition_name = N'AlwaysOnArDataSynchronizationHealthCondition'
set @expression = N'<Group>
<TypeClass>Bool</TypeClass>
<Count>1</Count>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>OR</OpType>
<Count>2</Count>
<Group>
<TypeClass>Bool</TypeClass>
<Count>1</Count>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>AND</OpType>
<Count>2</Count>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>AvailabilityMode</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.AvailabilityReplicaAvailabilityMode</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>AsynchronousCommit</Value>
</Constant>
</Function>
</Operator>
<Group>
<TypeClass>Bool</TypeClass>
<Count>1</Count>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>OR</OpType>
<Count>2</Count>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>RollupSynchronizationState</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.AvailabilityReplicaRollupSynchronizationState</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Synchronizing</Value>
</Constant>
</Function>
</Operator>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>RollupSynchronizationState</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.AvailabilityReplicaRollupSynchronizationState</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Synchronized</Value>
</Constant>
</Function>
</Operator>
</Operator>
</Group>
</Operator>
</Group>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>RollupSynchronizationState</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.AvailabilityReplicaRollupSynchronizationState</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Synchronized</Value>
</Constant>
</Function>
</Operator>
</Operator>
</Group>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'AvailabilityReplica', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'AvailabilityReplica', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnArRoleHealthCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnArRoleHealthCondition...'
set @condition_name = N'AlwaysOnArRoleHealthCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>OR</OpType>
<Count>2</Count>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>Role</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.AvailabilityReplicaRole</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Primary</Value>
</Constant>
</Function>
</Operator>
<Operator>
<TypeClass>Bool</TypeClass>
<OpType>EQ</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>Role</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.AvailabilityReplicaRole</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Secondary</Value>
</Constant>
</Function>
</Operator>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'AvailabilityReplica', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'AvailabilityReplica', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Condition: AlwaysOnArJoinStateHealthCondition
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Condition: AlwaysOnArJoinStateHealthCondition'
set @condition_name = N'AlwaysOnArJoinStateHealthCondition'
set @expression = N'<Operator>
<TypeClass>Bool</TypeClass>
<OpType>NE</OpType>
<Count>2</Count>
<Attribute>
<TypeClass>Numeric</TypeClass>
<Name>JoinState</Name>
</Attribute>
<Function>
<TypeClass>Numeric</TypeClass>
<FunctionType>Enum</FunctionType>
<ReturnType>Numeric</ReturnType>
<Count>2</Count>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>Microsoft.SqlServer.Management.Smo.AvailabilityReplicaJoinState</Value>
</Constant>
<Constant>
<TypeClass>String</TypeClass>
<ObjType>System.String</ObjType>
<Value>NotJoined</Value>
</Constant>
</Function>
</Operator>'
IF EXISTS(SELECT condition_id FROM msdb.dbo.syspolicy_conditions WHERE name=@condition_name)
BEGIN
EXEC msdb.dbo.sp_syspolicy_update_condition @name=@condition_name, @description=N'',
@facet=N'AvailabilityReplica', @expression=@expression, @is_name_condition=0, @obj_name=N''
END
ELSE
BEGIN
EXEC msdb.dbo.sp_syspolicy_add_condition @name=@condition_name, @description=N'',
@facet=N'AvailabilityReplica', @expression=@expression, @is_name_condition=0, @obj_name=N'',@condition_id=0
END
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'CONDITION', @name=@condition_name, @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Policy : AlwaysOnAgReplicasConnectionHealthPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnAgReplicasConnectionHealthPolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41413'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41414'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnAgReplicasConnectionHealthPolicy_ObjectSet', @facet=N'IAvailabilityGroupState', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgReplicasConnectionHealthPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnAgReplicasConnectionHealthPolicy_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup', @type=N'AVAILABILITYGROUP', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnAgReplicasConnectionHealthPolicy', @condition_name=N'AlwaysOnAgReplicasConnectionHealthCondition', @policy_category=N'Availability group warnings (primary replica only)',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.agp7allconnected.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnAgReplicasConnectionHealthPolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgReplicasConnectionHealthPolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Policy : AlwaysOnAgReplicasDataSynchronizationHealthPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnAgReplicasDataSynchronizationHealthPolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41407'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41408'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy_ObjectSet', @facet=N'IAvailabilityGroupState', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup', @type=N'AVAILABILITYGROUP', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy', @condition_name=N'AlwaysOnAgReplicasDataSynchronizationHealthCondition', @policy_category=N'Availability group warnings (primary replica only)',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.agp4synchronizing.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgReplicasDataSynchronizationHealthPolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Policy : AlwaysOnAgReplicasRoleHealthPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnAgReplicasRoleHealthPolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41411'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41412'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnAgReplicasRoleHealthPolicy_ObjectSet', @facet=N'IAvailabilityGroupState', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgReplicasRoleHealthPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnAgReplicasRoleHealthPolicy_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup', @type=N'AVAILABILITYGROUP', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnAgReplicasRoleHealthPolicy', @condition_name=N'AlwaysOnAgReplicasRoleHealthCondition', @policy_category=N'Availability group warnings (primary replica only)',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.agp6allroleshealthy.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnAgReplicasRoleHealthPolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgReplicasRoleHealthPolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Policy : AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41409'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41410'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy_ObjectSet', @facet=N'IAvailabilityGroupState', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup', @type=N'AVAILABILITYGROUP', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy', @condition_name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthCondition', @policy_category=N'Availability group warnings (primary replica only)',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.agp5synchronized.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgSynchronousReplicasDataSynchronizationHealthPolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Policy : AlwaysOnDbrJoinStatePolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnDbrJoinStatePolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41423'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41424'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnDbrJoinStatePolicy_ObjectSet', @facet=N'DatabaseReplicaState', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnDbrJoinStatePolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnDbrJoinStatePolicy_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup/DatabaseReplicaState', @type=N'DATABASEREPLICASTATE', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup/DatabaseReplicaState', @level_name=N'DatabaseReplicaState', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnDbrJoinStatePolicy', @condition_name=N'AlwaysOnDbrJoinStateCondition', @policy_category=N'Availability database warnings',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.drp2joined.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnDbrJoinStatePolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnDbrJoinStatePolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
--Policy : AlwaysOnDbrSuspendStatePolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnDbrSuspendStatePolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41421'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41422'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnDbrSuspendStatePolicy_ObjectSet', @facet=N'DatabaseReplicaState', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnDbrSuspendStatePolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnDbrSuspendStatePolicy_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup/DatabaseReplicaState', @type=N'DATABASEREPLICASTATE', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup/DatabaseReplicaState', @level_name=N'DatabaseReplicaState', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnDbrSuspendStatePolicy', @condition_name=N'AlwaysOnDbrSuspendStateCondition', @policy_category=N'Availability database warnings',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.drp1notsuspended.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnDbrSuspendStatePolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnDbrSuspendStatePolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
--Policy : AlwaysOnAgOnlineStateHealthPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnAgOnlineStateHealthPolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41403'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41404'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnAgOnlineStateHealthPolicy_ObjectSet', @facet=N'IAvailabilityGroupState', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgOnlineStateHealthPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnAgOnlineStateHealthPolicy_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup', @type=N'AVAILABILITYGROUP', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnAgOnlineStateHealthPolicy', @condition_name=N'AlwaysOnAgOnlineStateHealthCondition', @policy_category=N'Availability group errors (any replica role)',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.agp2online.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnAgOnlineStateHealthPolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgOnlineStateHealthPolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
--Policy : AlwaysOnAgAutomaticFailoverHealthPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnAgAutomaticFailoverHealthPolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41405'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41406'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnAgAutomaticFailoverHealthPolicy_ObjectSet', @facet=N'IAvailabilityGroupState', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgAutomaticFailoverHealthPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnAgAutomaticFailoverHealthPolicy_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup', @type=N'AVAILABILITYGROUP', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnAgAutomaticFailoverHealthPolicy', @condition_name=N'AlwaysOnAgAutomaticFailoverHealthCondition', @policy_category=N'Availability group errors (primary replica only)',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.agp3autofailover.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnAgAutomaticFailoverHealthPolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgAutomaticFailoverHealthPolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
--Policy : AlwaysOnArConnectionHealthPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnArConnectionHealthPolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41417'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41418'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnArConnectionHealthPolicy_ObjectSet', @facet=N'AvailabilityReplica', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnArConnectionHealthPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnArConnectionHealthPolicy_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup/AvailabilityReplica', @type=N'AVAILABILITYREPLICA', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup/AvailabilityReplica', @level_name=N'AvailabilityReplica', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnArConnectionHealthPolicy', @condition_name=N'AlwaysOnArConnectionHealthCondition', @policy_category=N'Availability replica errors',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.arp2connected.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnArConnectionHealthPolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnArConnectionHealthPolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
--Policy : AlwaysOnDbrDataSynchronizationState
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnDbrDataSynchronizationState...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41425'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41426'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnDbrDataSynchronizationState_ObjectSet', @facet=N'DatabaseReplicaState', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnDbrDataSynchronizationState_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnDbrDataSynchronizationState_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup/DatabaseReplicaState', @type=N'DATABASEREPLICASTATE', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup/DatabaseReplicaState', @level_name=N'DatabaseReplicaState', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnDbrDataSynchronizationState', @condition_name=N'AlwaysOnDbrDataSynchronizationCondition', @policy_category=N'Availability database warnings',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.drp3datasynchealthy.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnDbrDataSynchronizationState_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnDbrDataSynchronizationState', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
--Policy : AlwaysOnArDataSynchronizationHealthPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnArDataSynchronizationHealthPolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41419'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41420'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnArDataSynchronizationHealthPolicy_ObjectSet', @facet=N'AvailabilityReplica', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnArDataSynchronizationHealthPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnArDataSynchronizationHealthPolicy_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup/AvailabilityReplica', @type=N'AVAILABILITYREPLICA', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup/AvailabilityReplica', @level_name=N'AvailabilityReplica', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnArDataSynchronizationHealthPolicy', @condition_name=N'AlwaysOnArDataSynchronizationHealthCondition', @policy_category=N'Availability replica warnings',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.arp3datasynchealthy.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnArDataSynchronizationHealthPolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnArDataSynchronizationHealthPolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
--Policy : AlwaysOnArRoleHealthPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnArRoleHealthPolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41415'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41416'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnArRoleHealthPolicy_ObjectSet', @facet=N'AvailabilityReplica', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnArRoleHealthPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnArRoleHealthPolicy_ObjectSet', @type_skeleton=N'Server/AvailabilityGroup/AvailabilityReplica', @type=N'AVAILABILITYREPLICA', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup/AvailabilityReplica', @level_name=N'AvailabilityReplica', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@alwayson_target_set_id, @type_skeleton=N'Server/AvailabilityGroup', @level_name=N'AvailabilityGroup', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnArRoleHealthPolicy', @condition_name=N'AlwaysOnArRoleHealthCondition', @policy_category=N'Availability replica errors',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.arp1rolehealthy.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnArRoleHealthPolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnArRoleHealthPolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
--Policy : AlwaysOnAgWSFClusterHealthPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnAgWSFClusterHealthPolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41401'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41402'
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'AlwaysOnAgWSFClusterHealthPolicy_ObjectSet', @facet=N'Server', @object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'OBJECTSET', @name=N'AlwaysOnAgWSFClusterHealthPolicy_ObjectSet', @marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'AlwaysOnAgWSFClusterHealthPolicy_ObjectSet', @type_skeleton=N'Server', @type=N'SERVER', @enabled=True, @target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'AlwaysOnAgWSFClusterHealthPolicy', @condition_name=N'AlwaysOnAgWSFClusterHealthCondition', @policy_category=N'Availability group errors (any replica role)',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext, @help_link=N'swb.agdashboard.agp1WSFCquorum.issues.f1', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=0, @is_enabled=False, @policy_id=0, @root_condition_name=N'IsHadrEnabled', @object_set=N'AlwaysOnAgWSFClusterHealthPolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system @type=N'POLICY', @name=N'AlwaysOnAgWSFClusterHealthPolicy', @marker=1
-------------------------------------------------------------------------------------------------------------------------------------------------------------
--Policy : AlwaysOnArJoinStateHealthPolicy
-------------------------------------------------------------------------------------------------------------------------------------------------------------
PRINT ''
PRINT 'Creating Policy: AlwaysOnArJoinStateHealthPolicy...'
select @alwayson_policy_helptext = @alwayson_policy_helptext_prefix + '41427'
select @alwayson_policy_description = @alwayson_policy_description_prefix + '41428'
EXEC msdb.dbo.sp_syspolicy_add_object_set
@object_set_name=N'AlwaysOnArJoinStateHealthPolicy_ObjectSet',
@facet=N'AvailabilityReplica',
@object_set_id=0
EXEC msdb.dbo.sp_syspolicy_mark_system
@type=N'OBJECTSET',
@name=N'AlwaysOnArJoinStateHealthPolicy_ObjectSet',
@marker=1
EXEC msdb.dbo.sp_syspolicy_add_target_set
@object_set_name=N'AlwaysOnArJoinStateHealthPolicy_ObjectSet',
@type_skeleton=N'Server/AvailabilityGroup/AvailabilityReplica',
@type=N'AVAILABILITYREPLICA',
@enabled=True,
@target_set_id=@alwayson_target_set_id OUTPUT
EXEC msdb.dbo.sp_syspolicy_add_target_set_level
@target_set_id=@alwayson_target_set_id,
@type_skeleton=N'Server/AvailabilityGroup/AvailabilityReplica',
@level_name=N'AvailabilityReplica',
@condition_name=N'',
@target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level
@target_set_id=@alwayson_target_set_id,
@type_skeleton=N'Server/AvailabilityGroup',
@level_name=N'AvailabilityGroup',
@condition_name=N'',
@target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_policy
@name=N'AlwaysOnArJoinStateHealthPolicy',
@condition_name=N'AlwaysOnArJoinStateHealthCondition',
@policy_category=N'Availability replica warnings',
@description=@alwayson_policy_description,
@help_text=@alwayson_policy_helptext,
@help_link=N'sql11.swb.agdashboard.arp4joinstate.issues.f1',
@schedule_uid=N'00000000-0000-0000-0000-000000000000',
@execution_mode=0,
@is_enabled=False,
@policy_id=0,
@root_condition_name=N'IsHadrEnabled',
@object_set=N'AlwaysOnArJoinStateHealthPolicy_ObjectSet'
EXEC msdb.dbo.sp_syspolicy_mark_system
@type=N'POLICY',
@name=N'AlwaysOnArJoinStateHealthPolicy',
@marker=1
End
DROP PROCEDURE #sp_syspolicy_cascade_delete_policy
go
/**********************************************************************/
/* MSDB_SECURITY.SQL */
/* */
/* This is run after all the components are installed in MSDB */
/* It will set up the security and certificates. */
/* TODO: Split this too based on each component. */
/* */
/* */
/* Copyright (c) Microsoft Corporation */
/* All Rights Reserved. */
/* */
/**********************************************************************/
PRINT ''
PRINT '-------------------------------------------'
PRINT 'Starting execution of MSDB_POST_INSTALL.SQL'
PRINT '-------------------------------------------'
go
/**************************************************************/
/* Mark system objects */
/**************************************************************/
declare @start datetime
,@name sysname
select @start = start from #InstMsdb
-- As a temporary solution, exclude the syscollector_collection_sets table from being a system table
declare newsysobjs cursor for select name from sys.objects where schema_id = 1 and create_date >= @start
open newsysobjs
fetch next from newsysobjs into @name
while @@fetch_status = 0
begin
Exec sp_MS_marksystemobject @name
update #sp_table set bNewProc = 1 where name = @name
fetch next from newsysobjs into @name
end
deallocate newsysobjs
drop table #InstMsdb
go
PRINT 'Signing sps ...'
-- Create certificate to sign Agent sps
--
declare @certError int
if exists (select * from sys.certificates where name = '##MS_AgentSigningCertificate##')
begin
PRINT 'Dropping existing Agent certificate ...'
drop certificate [##MS_AgentSigningCertificate##]
select @certError = @@error
IF (@certError <> 0)
BEGIN
select 'Cannot drop existing certificate. Objects still signed by ##MS_AgentSigningCertificate##' = object_name(crypts.major_id)
from sys.crypt_properties crypts, sys.certificates certs
where crypts.thumbprint = certs.thumbprint
and crypts.class = 1
and certs.name = '##MS_AgentSigningCertificate##'
RAISERROR('Cannot drop existing ##MS_AgentSigningCertificate## in msdb. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
END
end
-- If the temp table #SqlAgentSignatures exists, then this script is running as part
-- of an upgrade from a previous build of sql server. In this case we want to sign
-- the Agent procedures using the same signatures that exist in a clean install
-- of this same build. Those signatures are in #SqlAgentSignatures. To do this
-- we create the certificate from the .cer file.
--
-- In the non-upgrade case, meaning that this script is being run during the build
-- of the SQL Server product itself, we simply create the certificate from scratch.
CREATE TABLE #InstmsdbAgentCertPath (AgentCert NVARCHAR(1100))
DECLARE @certificate_name NVARCHAR(1100) -- space for path + MS_AgentSigningCertificate.cer
IF (NOT OBJECT_ID(N'tempdb.dbo.#SqlAgentSignatures', 'U') IS NULL)
BEGIN
-- We need agent XP's to be on in order to lookup the path to our instance install folder.
DECLARE @advopt_old_value int
DECLARE @comp_old_value int
EXEC #sp_enable_component 'Agent XPs', @advopt_old_value out, @comp_old_value out
DECLARE @InstallRootPath nvarchar(1024)
-- Note: This is an _instance_ registry lookup, so it will
-- automatically insert the right instance name after the "Microsoft
-- SQL Server" part of the path, thus looking in a path like
-- 'SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10.INST1\Setup'
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\Microsoft SQL Server\Setup', N'SQLPath', @InstallRootPath OUTPUT
-- Restore Agent XPs to previous state
EXECUTE #sp_restore_component_state 'Agent XPs', @advopt_old_value, @comp_old_value
IF @InstallRootPath IS NULL
BEGIN
RAISERROR('Cannot find instance-specific registry path for SOFTWARE\Microsoft\Microsoft SQL Server\Setup\SqlPath. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
END
-- Now find our certificate in the Install folder, placed there by setup.
SELECT @InstallRootPath = @InstallRootPath + N'\Install'
select @certificate_name = @InstallRootPath + N'\MS_AgentSigningCertificate.cer'
-- Remember this file path so we can import it into master later
insert #InstmsdbAgentCertPath(AgentCert) VALUES (@certificate_name)
PRINT 'Updated #InstmsdbAgentCertPath with value ' + @certificate_name
-- Handle single quotes in the directory name since this string is going to be passed to EXECUTE
DECLARE @certificate_nameQuoted NVARCHAR(2200)
SELECT @certificate_nameQuoted = '''' + REPLACE(@certificate_name, '''', '''''') + ''''
PRINT 'Creating ##MS_AgentSigningCertificate## from ' + @certificate_name
EXECUTE(N'create certificate [##MS_AgentSigningCertificate##] from file = ' + @certificate_nameQuoted)
select @certError = @@error
IF (@certError <> 0)
BEGIN
RAISERROR('Cannot create ##MS_AgentSigningCertificate## from file. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
END
END
ELSE
BEGIN
dbcc traceon(4606,-1) -- Ignore domain policy about weak password
create certificate [##MS_AgentSigningCertificate##]
encryption by password = 'Yukon90_'
with subject = 'MS_AgentSigningCertificate'
select @certError = @@error
dbcc traceoff(4606,-1)
IF (@certError <> 0)
BEGIN
RAISERROR('Cannot create ##MS_AgentSigningCertificate## in msdb. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
END
--Use master database to get the path to the 'Data' folder
-- Note: master.dbo.sysaltfiles's filename column is 260 nvarchars
DECLARE @dataDirName NVARCHAR(520)
SELECT @dataDirName = SUBSTRING(physical_name, 1, CHARINDEX(N'master.mdf', LOWER(physical_name)) - 1)
FROM master.sys.master_files
WHERE (name = N'master')
if (@dataDirName is null)
RAISERROR('Cannot deduce path for temporary certificate ##MS_AgentSigningCertificate##. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
SELECT @certificate_name = @dataDirName + 'MS_AgentSigningCertificate.cer'
-- Remember this file path so we can import it into master later
insert #InstmsdbAgentCertPath(AgentCert) VALUES (@certificate_name)
PRINT 'Created #InstmsdbAgentCertPath with value ' + @certificate_name
END
go
BEGIN TRANSACTION
declare @sp sysname
declare @exec_str nvarchar(1024)
declare @sign int
declare @obdComponent int
declare @bNewProc int
declare @bUseExistingSignature int
set @bUseExistingSignature = 0
IF (NOT OBJECT_ID(N'tempdb.dbo.#SqlAgentSignatures', 'U') IS NULL)
BEGIN
set @bUseExistingSignature = 1
END
declare @err_str nvarchar(1024)
declare ms_crs_sps cursor global for select name, sign, obdComponent, bNewProc from #sp_table
open ms_crs_sps
fetch next from ms_crs_sps into @sp, @sign, @obdComponent, @bNewProc
while @@fetch_status = 0
begin
if exists(select * from sys.objects where name = @sp)
begin
print 'processing sp: ' + @sp
if (@sign = 1)
begin
if (@bUseExistingSignature = 1)
begin
declare @signature varbinary(max)
select @signature = signature
from #SqlAgentSignatures
where object_name = @sp
if (@signature is null)
begin
set @err_str = 'Cannot find existing signature for stored procedure ' + @sp + '. Terminating.'
RAISERROR(@err_str, 20, 127) WITH LOG
ROLLBACK TRANSACTION
return
end
set @exec_str = N'add signature to ' + @sp + N' by certificate [##MS_AgentSigningCertificate##] with signature = ' + CONVERT(nvarchar(max), @signature, 1)
end
else
begin
set @exec_str = N'add signature to ' + @sp + N' by certificate [##MS_AgentSigningCertificate##] with password = ''Yukon90_'''
end
Execute(@exec_str)
if (@@error <> 0)
begin
set @err_str = 'Cannot sign stored procedure ' + @sp + '. Terminating.'
RAISERROR(@err_str, 20, 127) WITH LOG
ROLLBACK TRANSACTION
return
end
end
-- If there is a new procedure that goes in a component, put it there
if (@obdComponent > 0 and @bNewProc > 0)
begin
if (@obdComponent = 1) -- SQLAgent
set @exec_str = N'exec sp_AddFunctionalUnitToComponent N''Agent XPs'', N''' + @sp + N''''
else if (@obdComponent = 2) -- DbMail
set @exec_str = N'exec sp_AddFunctionalUnitToComponent N''Database Mail XPs'', N''' + @sp + N''''
Execute(@exec_str)
if (@@error <> 0)
begin
RAISERROR('Cannot add stored procedure to component. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
ROLLBACK TRANSACTION
return
end
end
end
fetch next from ms_crs_sps into @sp, @sign, @obdComponent, @bNewProc
end
close ms_crs_sps
deallocate ms_crs_sps
COMMIT TRANSACTION
go
drop table #sp_table
go
PRINT 'Succesfully signed sps'
DECLARE @certificate_name NVARCHAR(1100)
select @certificate_name = AgentCert
from #InstmsdbAgentCertPath
-- Handle single quotes in the directory name since this string is going to be passed to EXECUTE
-- in both BACKUP CERT and CREATE CERT below.
DECLARE @certificate_nameQuoted NVARCHAR(2200)
SELECT @certificate_nameQuoted = '''' + REPLACE(@certificate_name, '''', '''''') + ''''
-- If this is not an upgrade, then we made our certificate from scratch.
-- Export it to a new file so that it can be imported into the master database.
IF (OBJECT_ID(N'tempdb.dbo.#SqlAgentSignatures', 'U') IS NULL)
BEGIN
-- Drop certificate private key. When we export to a file just below,
-- the file will not include the private key.
alter certificate [##MS_AgentSigningCertificate##] remove private key
IF (@@error <> 0)
RAISERROR('Cannot alter ##MS_AgentSigningCertificate## in msdb. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
-- Now we export the certificate to a file so that it can be imported into the master database.
-- Use the data directory to persist the file.
--
if (@certificate_name is null)
RAISERROR('Cannot deduce path for temporary certificate ##MS_AgentSigningCertificate##.', 20, 127) WITH LOG
declare @certError int
PRINT 'Exporting ##MS_AgentSigningCertificate## to ' + @certificate_name
BEGIN TRY
EXECUTE(N'backup certificate [##MS_AgentSigningCertificate##] to file = ' + @certificate_nameQuoted)
select @certError = @@error
END TRY
BEGIN CATCH
-- Error 15240 happens when instmsdb.sql is run repeatedly and directly on a sql server, so the
-- certificate already exists on disk and so the file cannot be written.
-- It should not happen during the mkmastr build stage since the .cer file was already deleted.
if (ERROR_NUMBER() != 15240)
BEGIN
select @certError = ERROR_NUMBER()
PRINT 'Error ' + @certError + ' backing up certificate.'
END
ELSE
BEGIN
PRINT 'Could not export certificate, trying again with random name. If this is a mkmastr build then this is an error.'
SELECT @certificate_name = SUBSTRING(@certificate_name, 1, CHARINDEX(N'.cer', @certificate_name) - 1) +
CONVERT(NVARCHAR(520), NEWID()) + N'.cer'
SELECT @certificate_nameQuoted = '''' + REPLACE(@certificate_name, '''', '''''') + ''''
update #InstmsdbAgentCertPath set AgentCert = @certificate_name
PRINT 'Exporting ##MS_AgentSigningCertificate## to ' + @certificate_name
EXECUTE(N'backup certificate [##MS_AgentSigningCertificate##] to file = ' + @certificate_nameQuoted)
select @certError = @@error
END
END CATCH
IF (@certError <> 0)
RAISERROR('Cannot backup ##MS_AgentSigningCertificate##. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
END
drop table #InstmsdbAgentCertPath
-- Now we want to grant the signed stored procedures access to the
-- master database. To allow the cross-database call from msdb, we
-- will recreate the Agent certificate in the master database and
-- grant execute permission to it.
-- Switch to master so the certificate is recreated there
use master
if exists (select * from sys.database_principals where name = '##MS_AgentSigningCertificate##')
drop user [##MS_AgentSigningCertificate##]
if exists (select * from sys.server_principals where name = '##MS_AgentSigningCertificate##')
drop login [##MS_AgentSigningCertificate##]
if exists (select * from sys.certificates where name = '##MS_AgentSigningCertificate##')
drop certificate [##MS_AgentSigningCertificate##]
-- Recreate the certificate (minus the private key, which we dropped earlier) from the file
-- into the master database.
PRINT 'Creating ##MS_AgentSigningCertificate## in master from ' + @certificate_name
execute(N'create certificate [##MS_AgentSigningCertificate##] from file = ' + @certificate_nameQuoted)
IF (@@error <> 0)
RAISERROR('Cannot create ##MS_AgentSigningCertificate## certificate in master. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
-- create a login in the master database based on this certicate.
--
create login [##MS_AgentSigningCertificate##] from certificate [##MS_AgentSigningCertificate##]
IF (@@error <> 0)
RAISERROR('Cannot create ##MS_AgentSigningCertificate## login. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
-- create certificate-based user for execution granting
--
create user [##MS_AgentSigningCertificate##] for certificate [##MS_AgentSigningCertificate##]
IF (@@error <> 0)
RAISERROR('Cannot create ##MS_AgentSigningCertificate## user. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
-- enable certificate for OBD
--
exec sys.sp_SetOBDCertificate N'##MS_AgentSigningCertificate##',N'ON'
grant execute to [##MS_AgentSigningCertificate##]
PRINT 'Successfully granted execute permission in master to ##MS_AgentSigningCertificate##.'
use msdb
go
--
-- End of signing sps
go
if not exists (select * from [dbo].[sysssispackagefolders] where [folderid] = '00000000-0000-0000-0000-000000000000')
BEGIN
-- Insert our root folder
DECLARE @advopt_old_value INT
DECLARE @comp_old_value INT
EXECUTE #sp_enable_component 'Agent XPs', @advopt_old_value out, @comp_old_value out
EXEC sp_ssis_addfolder NULL, '', '00000000-0000-0000-0000-000000000000'
-- Insert the 'Maintenance Plans' node at the root.
-- Note this GUID must never change - 08aa12d5-8f98-4dab-a4fc-980b150a5dc8
EXEC sp_ssis_addfolder '00000000-0000-0000-0000-000000000000', 'Maintenance Plans', '08aa12d5-8f98-4dab-a4fc-980b150a5dc8'
EXECUTE #sp_restore_component_state 'Agent XPs', @advopt_old_value, @comp_old_value
END
GO
/**************************************************************/
/* Enable Logshipping (Yukon) */
/**************************************************************/
declare @retcode int
exec @retcode = sys.sp_logshippinginstallmetadata
if (@retcode = 0)
begin
raiserror('Logshipping enabled successfully', 10, 1)
end
else
begin
raiserror('Logshipping not enabled for this edition', 10, 1)
end
go
/**************************************************************/
/* Drop auxilary procedure to enable OBD component */
/**************************************************************/
DROP PROCEDURE #sp_enable_component
go
DROP PROCEDURE #sp_restore_component_state
go
-- enable policy checking
IF EXISTS (SELECT * FROM sys.server_triggers WHERE name = N'syspolicy_server_trigger')
ENABLE TRIGGER [syspolicy_server_trigger] ON ALL SERVER
-- Restore old state of 'allow updates'
EXECUTE master.dbo.sp_configure N'allow updates', 0
go
RECONFIGURE WITH OVERRIDE
go
PRINT ''
PRINT '-------------------------------------------'
PRINT 'Execution of MSDB_POST_INSTALL.SQL complete'
PRINT '-------------------------------------------'
go
CHECKPOINT
go
use msdb
go
DECLARE @CMDExec sysname
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent\SubSystems',
N'CmdExec',
@CMDExec OUTPUT,
N'no_output'
IF @CMDExec IS NOT NULL
BEGIN
PRINT ''
PRINT 'Remove subsystem definition from registry...'
--remove subsystem definition from registry and populate subsystem table
DECLARE @ret INT
EXEC @ret = master..xp_instance_regdeletekey N'HKEY_LOCAL_MACHINE',
N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent\SubSystems'
IF @ret <> 0
RAISERROR('Failed to remove subsystems definition from registry', 10, 127)
END
PRINT ''
PRINT 'Populate syssubsystem table...'
EXEC @ret = sp_enum_sqlagent_subsystems
IF @ret <> 0
RAISERROR('Failed to add subsystems definition to syssubsystem table. Upgrade script terminating', 20, 127) WITH LOG
go
--restore Shiloh object permission
DECLARE @state_desc nvarchar(60)
DECLARE @permission_name sysname
DECLARE @object_name sysname
DECLARE @grantee_name sysname
DECLARE perms_set_cursor CURSOR LOCAL FOR
SELECT state_desc, permission_name, object_name, grantee_name from msdb.dbo.upgrade_perms
OPEN perms_set_cursor
FETCH NEXT FROM perms_set_cursor INTO @state_desc, @permission_name, @object_name, @grantee_name
WHILE (@@fetch_status = 0)
BEGIN
--PRINT @state_desc + N' ' + @permission_name + N' ON ' + @object_name + N' TO ' + @grantee_name
BEGIN TRY
EXEC (@state_desc + N' ' + @permission_name + N' ON ' + @object_name + N' TO ' + @grantee_name)
END TRY
BEGIN CATCH
END CATCH
FETCH NEXT FROM perms_set_cursor INTO @state_desc, @permission_name, @object_name, @grantee_name
END
DEALLOCATE perms_set_cursor
--remove public from SQLAgent Shiloh procedures
PRINT ''
PRINT 'Revoke any permission to public role...'
BEGIN TRY
REVOKE ALL ON sp_add_alert FROM PUBLIC
REVOKE ALL ON sp_add_category FROM PUBLIC
REVOKE ALL ON sp_add_job FROM PUBLIC
REVOKE ALL ON sp_add_jobschedule FROM PUBLIC
REVOKE ALL ON sp_add_jobserver FROM PUBLIC
REVOKE ALL ON sp_add_jobstep FROM PUBLIC
REVOKE ALL ON sp_add_notification FROM PUBLIC
REVOKE ALL ON sp_add_operator FROM PUBLIC
REVOKE ALL ON sp_add_targetservergroup FROM PUBLIC
REVOKE ALL ON sp_add_targetsvrgrp_member FROM PUBLIC
REVOKE ALL ON sp_apply_job_to_targets FROM PUBLIC
REVOKE ALL ON sp_convert_jobid_to_char FROM PUBLIC
REVOKE ALL ON sp_delete_alert FROM PUBLIC
REVOKE ALL ON sp_delete_all_msx_jobs FROM PUBLIC
REVOKE ALL ON sp_delete_category FROM PUBLIC
REVOKE ALL ON sp_delete_job FROM PUBLIC
REVOKE ALL ON sp_delete_job_references FROM PUBLIC
REVOKE ALL ON sp_delete_jobschedule FROM PUBLIC
REVOKE ALL ON sp_delete_jobserver FROM PUBLIC
REVOKE ALL ON sp_delete_jobstep FROM PUBLIC
REVOKE ALL ON sp_delete_notification FROM PUBLIC
REVOKE ALL ON sp_delete_operator FROM PUBLIC
REVOKE ALL ON sp_delete_targetserver FROM PUBLIC
REVOKE ALL ON sp_delete_targetservergroup FROM PUBLIC
REVOKE ALL ON sp_delete_targetsvrgrp_member FROM PUBLIC
REVOKE ALL ON sp_downloaded_row_limiter FROM PUBLIC
REVOKE ALL ON sp_generate_server_description FROM PUBLIC
REVOKE ALL ON sp_generate_target_server_job_assignment_sql FROM PUBLIC
REVOKE ALL ON sp_get_chunked_jobstep_params FROM PUBLIC
REVOKE ALL ON sp_get_composite_job_info FROM PUBLIC
REVOKE ALL ON sp_get_job_alerts FROM PUBLIC
REVOKE ALL ON sp_get_jobstep_db_username FROM PUBLIC
REVOKE ALL ON sp_get_message_description FROM PUBLIC
REVOKE ALL ON sp_get_schedule_description FROM PUBLIC
REVOKE ALL ON sp_get_sqlagent_properties FROM PUBLIC
REVOKE ALL ON sp_help_alert FROM PUBLIC
REVOKE ALL ON sp_help_category FROM PUBLIC
REVOKE ALL ON sp_help_downloadlist FROM PUBLIC
REVOKE ALL ON sp_help_job FROM PUBLIC
REVOKE ALL ON sp_help_jobhistory FROM PUBLIC
REVOKE ALL ON sp_help_jobschedule FROM PUBLIC
REVOKE ALL ON sp_help_jobserver FROM PUBLIC
REVOKE ALL ON sp_help_jobstep FROM PUBLIC
REVOKE ALL ON sp_help_notification FROM PUBLIC
REVOKE ALL ON sp_help_operator FROM PUBLIC
REVOKE ALL ON sp_help_operator_jobs FROM PUBLIC
REVOKE ALL ON sp_help_targetserver FROM PUBLIC
REVOKE ALL ON sp_help_targetservergroup FROM PUBLIC
REVOKE ALL ON sp_is_sqlagent_starting FROM PUBLIC
REVOKE ALL ON sp_jobhistory_row_limiter FROM PUBLIC
REVOKE ALL ON sp_manage_jobs_by_login FROM PUBLIC
REVOKE ALL ON sp_msx_defect FROM PUBLIC
REVOKE ALL ON sp_msx_enlist FROM PUBLIC
REVOKE ALL ON sp_multi_server_job_summary FROM PUBLIC
REVOKE ALL ON sp_post_msx_operation FROM PUBLIC
REVOKE ALL ON sp_purge_jobhistory FROM PUBLIC
REVOKE ALL ON sp_remove_job_from_targets FROM PUBLIC
REVOKE ALL ON sp_resync_targetserver FROM PUBLIC
REVOKE ALL ON sp_sem_add_message FROM PUBLIC
REVOKE ALL ON sp_sem_drop_message FROM PUBLIC
REVOKE ALL ON sp_set_local_time FROM PUBLIC
REVOKE ALL ON sp_set_sqlagent_properties FROM PUBLIC
REVOKE ALL ON sp_sqlagent_check_msx_version FROM PUBLIC
REVOKE ALL ON sp_sqlagent_get_perf_counters FROM PUBLIC
REVOKE ALL ON sp_sqlagent_get_startup_info FROM PUBLIC
REVOKE ALL ON sp_sqlagent_has_server_access FROM PUBLIC
REVOKE ALL ON sp_sqlagent_log_jobhistory FROM PUBLIC
REVOKE ALL ON sp_sqlagent_notify FROM PUBLIC
REVOKE ALL ON sp_sqlagent_probe_msx FROM PUBLIC
REVOKE ALL ON sp_sqlagent_refresh_job FROM PUBLIC
REVOKE ALL ON sp_start_job FROM PUBLIC
REVOKE ALL ON sp_stop_job FROM PUBLIC
REVOKE ALL ON sp_target_server_summary FROM PUBLIC
REVOKE ALL ON sp_uniquetaskname FROM PUBLIC
REVOKE ALL ON sp_update_alert FROM PUBLIC
REVOKE ALL ON sp_update_category FROM PUBLIC
REVOKE ALL ON sp_update_job FROM PUBLIC
REVOKE ALL ON sp_update_jobschedule FROM PUBLIC
REVOKE ALL ON sp_update_jobstep FROM PUBLIC
REVOKE ALL ON sp_update_notification FROM PUBLIC
REVOKE ALL ON sp_update_operator FROM PUBLIC
REVOKE ALL ON sp_update_targetservergroup FROM PUBLIC
REVOKE ALL ON sp_verify_alert FROM PUBLIC
REVOKE ALL ON sp_verify_category FROM PUBLIC
REVOKE ALL ON sp_verify_job FROM PUBLIC
REVOKE ALL ON sp_verify_job_date FROM PUBLIC
REVOKE ALL ON sp_verify_job_identifiers FROM PUBLIC
REVOKE ALL ON sp_verify_job_time FROM PUBLIC
REVOKE ALL ON sp_verify_jobproc_caller FROM PUBLIC
REVOKE ALL ON sp_verify_jobstep FROM PUBLIC
REVOKE ALL ON sp_verify_notification FROM PUBLIC
REVOKE ALL ON sp_verify_operator FROM PUBLIC
REVOKE ALL ON sp_verify_performance_condition FROM PUBLIC
REVOKE ALL ON sp_verify_subsystem FROM PUBLIC
END TRY
BEGIN CATCH
END CATCH
go
--remove public permission from Shiloh objects that have been secured in Shiloh and overwritten during instmsdb.sql
--create a temporary table with objects granted to public during execution of instmsdb.sql
CREATE TABLE #instmsdb_public_objects(object_name sysname)
INSERT INTO #instmsdb_public_objects VALUES (N'backupfile')
INSERT INTO #instmsdb_public_objects VALUES (N'backupmediafamily')
INSERT INTO #instmsdb_public_objects VALUES (N'backupmediaset')
INSERT INTO #instmsdb_public_objects VALUES (N'backupset')
INSERT INTO #instmsdb_public_objects VALUES (N'restorehistory')
INSERT INTO #instmsdb_public_objects VALUES (N'restorefile')
INSERT INTO #instmsdb_public_objects VALUES (N'restorefilegroup')
INSERT INTO #instmsdb_public_objects VALUES (N'logmarkhistory')
INSERT INTO #instmsdb_public_objects VALUES (N'suspect_pages')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_get_dtsversion')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_make_dtspackagename')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_add_dtspackage')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_drop_dtspackage')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_reassign_dtspackageowner')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_get_dtspackage')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_enum_dtspackages')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_log_dtspackage_begin')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_log_dtspackage_end')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_log_dtsstep_begin')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_log_dtsstep_end')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_log_dtstask')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_enum_dtspackagelog')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_enum_dtssteplog')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_enum_dtstasklog')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_dump_dtslog_all')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_dump_dtspackagelog')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_dump_dtssteplog')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_dump_dtstasklog')
go
DECLARE @object_name sysname
DECLARE @tsql nvarchar(300)
DECLARE public_remove_cursor CURSOR LOCAL FOR
SELECT object_name FROM #instmsdb_public_objects
OPEN public_remove_cursor
FETCH NEXT FROM public_remove_cursor INTO @object_name
WHILE (@@fetch_status = 0)
BEGIN
--PRINT @state_desc + N' ' + @permission_name + N' ON ' + @object_name + N' TO ' + @grantee_name
BEGIN TRY
--if this object exists in 8.0 msdb and is granted to public no op otherwise remove permission to public on it
IF (EXISTS (SELECT * FROM msdb.dbo.upgrade_perms
WHERE UPPER(object_name collate SQL_Latin1_General_CP1_CS_AS ) = UPPER(@object_name collate SQL_Latin1_General_CP1_CS_AS )))
AND (NOT EXISTS (SELECT * FROM msdb.dbo.upgrade_perms WHERE object_name = @object_name
AND UPPER(grantee_name collate SQL_Latin1_General_CP1_CS_AS ) = N'PUBLIC'))
BEGIN
SELECT @tsql = N'REVOKE ALL ON ' + QUOTENAME(@object_name) + N' FROM PUBLIC'
PRINT @tsql
EXEC (@tsql)
END
END TRY
BEGIN CATCH
END CATCH
FETCH NEXT FROM public_remove_cursor INTO @object_name
END
DEALLOCATE public_remove_cursor
go
DROP TABLE #instmsdb_public_objects
DROP TABLE msdb.dbo.upgrade_perms
go
--------------------------------------------------------------------------------
--update proxy account
--proxy update batch
--read sysadminonly flag
DECLARE @ret INT
DECLARE @proxy_id INT
DECLARE @job_id UNIQUEIDENTIFIER
DECLARE @step_id INT
DECLARE @subsystem sysname
DECLARE @owner_name NVARCHAR(256)
DECLARE @full_name sysname
DECLARE @owner_sid VARBINARY(85)
DECLARE @is_sysadmin INT
--walk throu all job steps excluding TSQL jobsteps
DECLARE jobsteps_cursor CURSOR LOCAL FOR
SELECT js.job_id, js.step_id, js.subsystem, SUSER_SNAME(j.owner_sid)
FROM sysjobs j JOIN sysjobsteps js ON j.job_id = js.job_id
WHERE UPPER(js.subsystem collate SQL_Latin1_General_CP1_CS_AS) <> N'TSQL'
AND SUSER_SNAME(j.owner_sid) IS NOT NULL
FOR READ ONLY
--wals thru all non sysadmin job owners
DECLARE job_nonsysadmin_owners_cursor CURSOR LOCAL FOR
SELECT DISTINCT j.owner_sid FROM sysjobs j
FOR READ ONLY
OPEN job_nonsysadmin_owners_cursor
FETCH NEXT FROM job_nonsysadmin_owners_cursor INTO @owner_sid
WHILE (@@fetch_status = 0)
BEGIN
SELECT @owner_name = SUSER_SNAME(@owner_sid)
IF @owner_name IS NOT NULL
BEGIN
--is job owner member of sysadmin role?
BEGIN TRY
EXECUTE AS LOGIN=@owner_name -- impersonate
SELECT @is_sysadmin = ISNULL(IS_SRVROLEMEMBER('sysadmin'),0) -- check role membership
REVERT -- revert back
END TRY
BEGIN CATCH
SET @is_sysadmin = 0
END CATCH
IF @is_sysadmin = 0
BEGIN
--add job_owner to the SQLAgentUserRole msdb role in order to permit the job owner to handle his jobs
--has this login a user in msdb?
IF NOT EXISTS(SELECT * FROM sys.database_principals WHERE (sid = @owner_sid) OR (LOWER(name collate SQL_Latin1_General_CP1_CS_AS) = LOWER(@owner_name collate SQL_Latin1_General_CP1_CS_AS)))
BEGIN
PRINT ''
PRINT 'Granting login access''' + @owner_name + ''' to msdb database...'
BEGIN TRY
EXEC sp_grantdbaccess @loginame = @owner_name
END TRY
BEGIN CATCH
RAISERROR('A problem was encountered granting access to MSDB database for login ''%s''. Make sure this login is provisioned with SQLServer and rerun sqlagent_msdb_upgrade.sql ', 10, 127) WITH LOG
END CATCH
END
PRINT ''
PRINT 'Adding user ''' + @owner_name + ''' to SQLAgentUserRole msdb role...'
BEGIN TRY
EXEC sp_addrolemember @rolename = 'SQLAgentUserRole', @membername = @owner_name
END TRY
BEGIN CATCH
RAISERROR('A problem was encountered adding user ''%s'' to SQLAgentUserRole. Make sure this is a valid user in MSDB database and rerun sqlagent_msdb_upgrade.sql ', 10, 127) WITH LOG
END CATCH
END
END
FETCH NEXT FROM job_nonsysadmin_owners_cursor INTO @owner_sid
END
DEALLOCATE job_nonsysadmin_owners_cursor
--credential created from LSA values in the file src\upgrade_scripts\sqlagent100_upgrade.sql
IF EXISTS (SELECT credential_id FROM master.sys.credentials WHERE name = N'UpgradedCredential')
BEGIN
IF (NOT EXISTS(SELECT * FROM sysproxies WHERE name = N'UpgradedProxyAccount'))
BEGIN
PRINT 'Update proxy account'
SELECT @ret = 0
--create the proxy first
PRINT ''
PRINT 'Adding Proxy...'
BEGIN TRY --prevent sp_add_proxy raising severity 16 error that will terminate upgrade scritp when proxy account has bad info
EXEC @ret = sp_add_proxy @proxy_name = N'UpgradedProxyAccount',
@credential_name = N'UpgradedCredential',
@proxy_id = @proxy_id OUTPUT
END TRY
BEGIN CATCH
SET @ret = 1
END CATCH
IF @ret <> 0
BEGIN
RAISERROR('A problem was encountered updating proxy account. Verify that user name and secret of credential [UpgradedCredential] are correct and rerun sqlagent_msdb_upgrade.sql ', 10, 127) WITH LOG
END
ELSE
BEGIN
OPEN jobsteps_cursor
FETCH NEXT FROM jobsteps_cursor INTO @job_id, @step_id, @subsystem, @owner_name
WHILE (@@fetch_status = 0)
BEGIN
--is job owner member of sysadmin role?
BEGIN TRY
EXECUTE AS LOGIN = @owner_name -- impersonate
SELECT @is_sysadmin = ISNULL(IS_SRVROLEMEMBER('sysadmin'),0) -- check role membership
REVERT -- revert back
END TRY
BEGIN CATCH
SET @is_sysadmin = 0
END CATCH
IF @is_sysadmin = 0
BEGIN
IF NOT EXISTS(SELECT * FROM sysproxysubsystem ps JOIN syssubsystems s
ON ps.subsystem_id = s.subsystem_id
WHERE s.subsystem = @subsystem
AND ps.proxy_id = @proxy_id)
BEGIN
PRINT 'Grant permission to proxy ''UpgradedProxyAccount'' for subsystem ''' + @subsystem + '''...'
BEGIN TRY
EXEC @ret = sp_grant_proxy_to_subsystem @subsystem_name = @subsystem,
@proxy_id = @proxy_id
END TRY
BEGIN CATCH
SET @ret = 1
END CATCH
IF @ret <> 0
BEGIN
RAISERROR('FAILED TO GRANT PERMISSION TO PROXY (%d) FOR SUBSYSTEM ''%s''.', 10, 127, @proxy_id, @subsystem ) WITH LOG
END
END
IF NOT EXISTS(SELECT * FROM sysproxylogin WHERE proxy_id = @proxy_id AND sid = SUSER_SID(@owner_name))
BEGIN
PRINT 'Grant login ''' + @owner_name + ''' permission to use proxy ''UpgradedProxyAccount'' for subsystem ''' + @subsystem + '''...'
BEGIN TRY
EXEC @ret = sp_grant_login_to_proxy @proxy_id = @proxy_id,
@login_name = @owner_name
END TRY
BEGIN CATCH
SET @ret = 1
END CATCH
IF @ret <> 0
BEGIN
RAISERROR('FAILED TO GRANT PERMISSION TO LOGIN ''%s'' FOR PROXY (%d).', 10, 127, @owner_name, @proxy_id) WITH LOG
END
END
--PRINT 'Update sysjobsteps...'
UPDATE sysjobsteps SET proxy_id = @proxy_id WHERE job_id = @job_id and step_id = @step_id
END --is_sysadmin = 0
FETCH NEXT FROM jobsteps_cursor INTO @job_id, @step_id, @subsystem, @owner_name
END --WHILE (@@fetch_status = 0)
CLOSE jobsteps_cursor
END
END -- NOT EXISTS(SELECT * FROM sysproxies WHERE name = N'UpgradedProxyAccount')
END -- EXISTS (SELECT credential_id FROM master.sys.credentials WHERE name = N'AgentCred80')
DEALLOCATE jobsteps_cursor
go
--msx proxy upgrade
DECLARE @credential_id INT
--credential created from 80 lSA values in the file src\upgrade_scripts\sqlagent100_upgrade.sql
IF EXISTS (SELECT credential_id FROM master.sys.credentials WHERE name = N'UpgradedMSXCredential')
BEGIN
SELECT @credential_id = credential_id FROM master.sys.credentials
WHERE name = N'UpgradedMSXCredential'
--set credential_id to agent registry
EXECUTE master.dbo.xp_instance_regwrite 'HKEY_LOCAL_MACHINE',
'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
'MSXCredentialID',
'REG_DWORD',
@credential_id
END
go
-- Complete replication job security meta-data upgrades
IF OBJECT_ID('sys.sp_vupgrade_replsecurity_metadata', 'P') IS NOT NULL
BEGIN
PRINT 'Performing replication job security meta-data upgrades...'
EXECUTE master.sys.sp_vupgrade_replsecurity_metadata
END
ELSE
BEGIN
-- "The replication security meta-data could not be upgraded for all database(s). Please ensure that entire server is upgraded and re-execute sp_vupgrade_replsecurity_metadata."
RAISERROR(21450, 10, -1, 'security meta-data', 'all', 'entire server', 'master.sys.sp_vupgrade_replsecurity_metadata') WITH LOG
END
GO
-- Log Shipping Upgrade
declare @retcode int
PRINT ''
PRINT 'Upgrading SQL Server Log Shipping...'
exec @retcode = master.sys.sp_upgrade_log_shipping
if @retcode != 0 or @@error != 0
begin
RAISERROR('Upgrade of Log Shipping for SQL Server did not complete successfully. After upgrade, re-execute sp_upgrade_log_shipping from master database.', 10, 1) WITH LOG
end
PRINT 'Upgraded SQL Server Log Shipping successfully.'
go
-----------------------------------------------------------------------------
--Drop legacy objects
CREATE TABLE #instmsdb_legacy_objects(object_name sysname, type_name sysname, type_id nvarchar(2))
--tables
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.mswebtasks', N'TABLE', N'T' )
--procedures
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_helphistory', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_helptask', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_insmswebtask', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_purgehistory', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_sem_get_perf_counter_help', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_updatetask', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_updmswebtask', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_verify_jobschedule', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_verifytaskid', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_check_localserver_name', N'PROCEDURE', N'P' )
--views
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sysalternates', N'VIEW', N'V' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.systasks', N'VIEW', N'V' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.systasks_view', N'VIEW', N'V' )
go
DECLARE @object_name sysname
DECLARE @type_name sysname
DECLARE @type_id nvarchar(2)
DECLARE @tsql nvarchar(300)
DECLARE legacy_remove_cursor CURSOR LOCAL FOR
SELECT object_name, type_name, type_id FROM #instmsdb_legacy_objects
OPEN legacy_remove_cursor
FETCH NEXT FROM legacy_remove_cursor INTO @object_name, @type_name, @type_id
WHILE (@@fetch_status = 0)
BEGIN
BEGIN TRY
IF (OBJECT_ID(@object_name, @type_id) IS NOT NULL)
BEGIN
SELECT @tsql = N'DROP ' + @type_name + N' ' + @object_name
PRINT @tsql
EXEC (@tsql)
END
END TRY
BEGIN CATCH
END CATCH
FETCH NEXT FROM legacy_remove_cursor INTO @object_name, @type_name, @type_id
END
CLOSE legacy_remove_cursor
DEALLOCATE legacy_remove_cursor
go
DROP TABLE #instmsdb_legacy_objects
go
--other legacy objects CTP15 to RTM only
BEGIN TRY
if exists (select * from sys.database_principals where name = 'MS_AgentSigningCertificateUser')
drop user MS_AgentSigningCertificateUser
if exists (select * from sys.server_principals where name = 'MS_AgentSigningCertificateLogin')
drop login MS_AgentSigningCertificateLogin
-- remove the MaintenanceUserRole role CTP15 to RTM only
IF (EXISTS (SELECT *
FROM msdb.dbo.sysusers
WHERE (name = N'MaintenanceUserRole')
AND (issqlrole = 1)))
BEGIN
BEGIN
EXECUTE msdb.dbo.sp_droprole @rolename = N'MaintenanceUserRole'
END
END
END TRY
BEGIN CATCH
END CATCH
go
PRINT ''
PRINT '------------------------------------------'
PRINT 'Execution of POST_SQLAGENT100.SQL complete'
PRINT '------------------------------------------'
go
-------------------------------------------------------------
PRINT '------------------------------------'
PRINT 'Moving 2005 SSIS Data to 2008 tables'
PRINT '------------------------------------'
--
-- Add the old roles to the new SSIS role membership
--
PRINT 'Mapping SSIS yukon roles to katmai roles...'
GO
if exists (select * from dbo.sysusers where [name] = N'db_dtsadmin' and [issqlrole] = 1)
BEGIN
EXEC sp_addrolemember N'db_ssisadmin', N'db_dtsadmin'
END
GO
if exists (select * from dbo.sysusers where [name] = N'db_dtsltduser' and [issqlrole] = 1)
BEGIN
EXEC sp_addrolemember N'db_ssisltduser', N'db_dtsltduser'
END
GO
if exists (select * from dbo.sysusers where [name] = N'db_dtsoperator' and [issqlrole] = 1)
BEGIN
EXEC sp_addrolemember N'db_ssisoperator', N'db_dtsoperator'
END
GO
--
-- Move folders from sysdtspackagefolders90 to sysssispackagefolders
--
PRINT 'Moving package folders...'
GO
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtspackagefolders90]') AND type = N'U')
INSERT INTO [msdb].[dbo].[sysssispackagefolders]
([folderid]
,[parentfolderid]
,[foldername])
SELECT [folderid]
,[parentfolderid]
,[foldername]
FROM [msdb].[dbo].[sysdtspackagefolders90]
WHERE [folderid] != '00000000-0000-0000-0000-000000000000' -- Root folder
AND [folderid] != '08aa12d5-8f98-4dab-a4fc-980b150a5dc8' -- Maintenance Plans
GO
--
-- Move packages from sysdtspackages90 to sysssispackages
--
PRINT 'Moving packages...'
GO
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtspackages90]') AND type = N'U')
INSERT INTO [msdb].[dbo].[sysssispackages]
([name]
,[id]
,[description]
,[createdate]
,[folderid]
,[ownersid]
,[packagedata]
,[packageformat]
,[packagetype]
,[vermajor]
,[verminor]
,[verbuild]
,[vercomments]
,[verid]
,[isencrypted]
,[readrolesid]
,[writerolesid])
SELECT [name]
,[id]
,[description]
,[createdate]
,[folderid]
,[ownersid]
,[packagedata]
,[packageformat]
,[packagetype]
,[vermajor]
,[verminor]
,[verbuild]
,[vercomments]
,[verid]
,[isencrypted]
,[readrolesid]
,[writerolesid]
FROM [msdb].[dbo].[sysdtspackages90]
GO
--
-- Move log data from sysdtslog90 to sysssislog
--
PRINT 'Moving logs...'
GO
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtslog90]') AND type = N'U')
INSERT INTO [msdb].[dbo].[sysssislog]
([event]
,[computer]
,[operator]
,[source]
,[sourceid]
,[executionid]
,[starttime]
,[endtime]
,[datacode]
,[databytes]
,[message])
SELECT [event]
,[computer]
,[operator]
,[source]
,[sourceid]
,[executionid]
,[starttime]
,[endtime]
,[datacode]
,[databytes]
,[message]
FROM [msdb].[dbo].[sysdtslog90]
GO
--
-- Drop yukon objects
--
PRINT 'Dropping yukon stored procedures...'
GO
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_setpackageroles]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_setpackageroles]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_getpackageroles]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_getpackageroles]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_deletepackage]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_deletepackage]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_getpackage]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_getpackage]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_putpackage]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_putpackage]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_checkexists]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_checkexists]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_listpackages]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_listpackages]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_addlogentry]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_addlogentry]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_deletefolder]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_deletefolder]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_addfolder]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_addfolder]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_renamefolder]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_renamefolder]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_getfolder]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_getfolder]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_listfolders]') AND type = N'P')
DROP PROCEDURE [dbo].[sp_dts_listfolders]
GO
PRINT 'Dropping yukon tables...'
GO
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtslog90]') AND type = N'U')
DROP TABLE [dbo].[sysdtslog90]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtspackages90]') AND type = N'U')
DROP TABLE [dbo].[sysdtspackages90]
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtspackagefolders90]') AND type = N'U')
DROP TABLE [dbo].[sysdtspackagefolders90]
GO
--
-- Create a view for the logs table for backwards compatibility
--
PRINT 'Creating sysdtslog90 view...'
GO
IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtslog90]') and type = N'V')
BEGIN
DROP VIEW [dbo].[sysdtslog90]
END
GO
CREATE VIEW [dbo].[sysdtslog90]
AS
SELECT [id]
,[event]
,[computer]
,[operator]
,[source]
,[sourceid]
,[executionid]
,[starttime]
,[endtime]
,[datacode]
,[databytes]
,[message]
FROM [msdb].[dbo].[sysssislog]
GO
-------------------------------------------------------------
/*********************************************************************/
/* Create auxilary procedure to enable OBD (Off By Default component */
/*********************************************************************/
IF (OBJECT_ID(N'tempdb..#sp_enable_component', 'P') IS NOT NULL)
BEGIN
DROP PROCEDURE [tempdb]..[#sp_enable_component]
END
GO
CREATE PROCEDURE #sp_enable_component
@comp_name sysname,
@advopt_old_value INT OUT,
@comp_old_value INT OUT
AS
BEGIN
SELECT @advopt_old_value=cast(value_in_use as int) from sys.configurations where name = 'show advanced options';
SELECT @comp_old_value=cast(value_in_use as int) from sys.configurations where name = @comp_name;
EXEC sp_configure 'show advanced options',1;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure @comp_name, 1;
RECONFIGURE WITH OVERRIDE;
END
go
IF (OBJECT_ID(N'tempdb..#sp_restore_component_state ', 'P') IS NOT NULL)
BEGIN
DROP PROCEDURE [tempdb]..[#sp_restore_component_state ]
END
GO
CREATE PROCEDURE #sp_restore_component_state
@comp_name sysname,
@advopt_old_value INT,
@comp_old_value INT
AS
BEGIN
EXEC sp_configure @comp_name, @comp_old_value;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'show advanced options',@advopt_old_value;
RECONFIGURE WITH OVERRIDE;
END
GO
/**************************************************************/
/* DMF Post-upgrade steps */
/**************************************************************/
--
-- >>> CTP5 -> CTP6 Upgrade
--
-- Restoring previously saved data and converting TargetSets to ObjectSets
IF (OBJECT_ID('dbo.dmf_upgrade', 'U') IS NOT NULL)
BEGIN
BEGIN TRANSACTION
-- Restore policies
SET IDENTITY_INSERT dbo.syspolicy_policies_internal ON
INSERT dbo.syspolicy_policies_internal (policy_id,name,condition_id,root_condition_id,date_created,execution_mode,policy_category_id,schedule_uid,description,help_text,help_link,is_enabled,job_id,created_by,modified_by,date_modified)
SELECT policy_id,name,condition_id,root_condition_id,date_created,execution_mode,policy_category_id,schedule_uid,description,help_text,help_link,is_enabled,job_id,created_by,modified_by,date_modified
FROM msdb.dbo.tmp_syspolicy_policies_internal
SET IDENTITY_INSERT dbo.syspolicy_policies_internal OFF
-- Restore Health state
SET IDENTITY_INSERT dbo.syspolicy_system_health_state_internal ON
INSERT dbo.syspolicy_system_health_state_internal (health_state_id,policy_id,last_run_date,target_query_expression_with_id,target_query_expression,result)
SELECT * FROM msdb.dbo.tmp_syspolicy_system_health_state_internal
SET IDENTITY_INSERT dbo.syspolicy_system_health_state_internal OFF
-- Restore Execution history
SET IDENTITY_INSERT dbo.syspolicy_policy_execution_history_internal ON
INSERT dbo.syspolicy_policy_execution_history_internal (history_id,policy_id,start_date,end_date,result,is_full_run,exception_message,exception)
SELECT * FROM msdb.dbo.tmp_syspolicy_policy_execution_history_internal
SET IDENTITY_INSERT dbo.syspolicy_policy_execution_history_internal OFF
SET IDENTITY_INSERT dbo.syspolicy_policy_execution_history_details_internal ON
INSERT dbo.syspolicy_policy_execution_history_details_internal (detail_id,history_id,target_query_expression,target_query_expression_with_id,execution_date,result,result_detail,exception_message,exception)
SELECT * FROM msdb.dbo.tmp_syspolicy_policy_execution_history_details_internal
SET IDENTITY_INSERT dbo.syspolicy_policy_execution_history_details_internal OFF
-- Convert TargetSets to ObjectSets
SET IDENTITY_INSERT dbo.syspolicy_target_sets_internal ON
DECLARE @policy_id int, @policy_name sysname, @facet nvarchar(max), @os_name sysname, @os_id int, @ts_id int
DECLARE ts_cur CURSOR FOR
SELECT p.policy_id, p.name, c.facet, ts.target_set_id
FROM msdb.dbo.tmp_syspolicy_target_sets_internal ts JOIN dbo.syspolicy_policies p ON (ts.policy_id = p.policy_id)
JOIN dbo.syspolicy_conditions c ON (p.condition_id = c.condition_id)
ORDER BY p.policy_id, ts.target_set_id
OPEN ts_cur
FETCH ts_cur INTO @policy_id , @policy_name , @facet, @ts_id
WHILE @@FETCH_STATUS = 0
BEGIN
-- make sure ObjectSet name is unique
SET @os_name = LEFT(@policy_name,118) + '_ObjectSet'
IF EXISTS (SELECT * FROM dbo.syspolicy_object_sets WHERE object_set_name = @os_name)
BEGIN
SET @os_name = LEFT(@policy_name,82) + CAST(NEWID() AS nchar(36)) + '_ObjectSet'
END
-- if we go through multi-TS ObjectSet we only need to add it once
-- cursor sort order guarantees @os_id remains correct
IF 0 = (SELECT ISNULL(object_set_id, 0) FROM syspolicy_policies WHERE policy_id = @policy_id)
BEGIN
Exec sp_syspolicy_add_object_set @os_name, @facet, @os_id OUTPUT
UPDATE syspolicy_policies_internal
SET object_set_id = @os_id
WHERE policy_id = @policy_id
END
INSERT syspolicy_target_sets_internal (target_set_id,object_set_id,type_skeleton,type,enabled)
SELECT target_set_id,@os_id,type_skeleton,type,1
FROM msdb.dbo.tmp_syspolicy_target_sets_internal WHERE target_set_id = @ts_id
FETCH ts_cur INTO @policy_id , @policy_name , @facet, @ts_id
END
CLOSE ts_cur
DEALLOCATE ts_cur
SET IDENTITY_INSERT dbo.syspolicy_target_sets_internal OFF
SET IDENTITY_INSERT dbo.syspolicy_target_set_levels_internal ON
INSERT syspolicy_target_set_levels_internal (target_set_level_id,target_set_id,type_skeleton,condition_id,level_name)
SELECT target_set_level_id,target_set_id,type_skeleton,condition_id,level_name
FROM msdb.dbo.tmp_syspolicy_target_set_levels_internal
SET IDENTITY_INSERT dbo.syspolicy_target_set_levels_internal OFF
-- Add missing levels for MultipartName sets
DECLARE @tsl_id int
SET @ts_id = 0
SET @tsl_id = 0
DECLARE @mpn_facet_id int
SELECT @mpn_facet_id = management_facet_id FROM dbo.syspolicy_management_facets
WHERE name = 'IMultipartNameFacet'
DECLARE os_cur CURSOR FOR
SELECT object_set_id
FROM dbo.syspolicy_object_sets_internal
WHERE facet_id = @mpn_facet_id
OPEN os_cur
FETCH os_cur INTO @os_id
WHILE @@FETCH_STATUS = 0
BEGIN
IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'PROCEDURE')
BEGIN
Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/StoredProcedure', @type='PROCEDURE', @enabled=0, @target_set_id = @ts_id OUTPUT
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/StoredProcedure', @condition_id=NULL, @level_name='StoredProcedure', @target_set_level_id=@tsl_id
END
IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'SYNONYM')
BEGIN
Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/Synonym', @type='SYNONYM', @enabled=0, @target_set_id = @ts_id OUTPUT
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/Synonym', @condition_id=NULL, @level_name='Synonym', @target_set_level_id=@tsl_id
END
IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'TABLE')
BEGIN
Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/Table', @type='TABLE', @enabled=0, @target_set_id = @ts_id OUTPUT
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/Table', @condition_id=NULL, @level_name='Table', @target_set_level_id=@tsl_id
END
IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'FUNCTION')
BEGIN
Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/UserDefinedFunction', @type='FUNCTION', @enabled=0, @target_set_id = @ts_id OUTPUT
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/UserDefinedFunction', @condition_id=NULL, @level_name='UserDefinedFunction', @target_set_level_id=@tsl_id
END
IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'TYPE')
BEGIN
Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/UserDefinedType', @type='TYPE', @enabled=0, @target_set_id = @ts_id OUTPUT
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/UserDefinedType', @condition_id=NULL, @level_name='UserDefinedType', @target_set_level_id=@tsl_id
END
IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'VIEW')
BEGIN
Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/View', @type='VIEW', @enabled=0, @target_set_id = @ts_id OUTPUT
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/View', @condition_id=NULL, @level_name='View', @target_set_level_id=@tsl_id
END
IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'XMLSCHEMACOLLECTION')
BEGIN
Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/XmlSchemaCollection', @type='XMLSCHEMACOLLECTION', @enabled=0, @target_set_id = @ts_id OUTPUT
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id
Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/XmlSchemaCollection', @condition_id=NULL, @level_name='XmlSchemaCollection', @target_set_level_id=@tsl_id
END
FETCH os_cur INTO @os_id
END
CLOSE os_cur
DEALLOCATE os_cur
-- Clean up upgrade marker
DROP TABLE dmf_upgrade
-- And temp tables
DROP TABLE msdb.dbo.tmp_syspolicy_target_sets_internal
DROP TABLE msdb.dbo.tmp_syspolicy_target_set_levels_internal
DROP TABLE msdb.dbo.tmp_syspolicy_policies_internal
DROP TABLE msdb.dbo.tmp_syspolicy_system_health_state_internal
DROP TABLE msdb.dbo.tmp_syspolicy_policy_execution_history_internal
DROP TABLE msdb.dbo.tmp_syspolicy_policy_execution_history_details_internal
COMMIT TRANSACTION
PRINT 'DMF successfully upgraded'
END
--
-- <<< CTP5 -> CTP6 Upgrade
--
-- Make sure Agent XPs are enabled regardless of the state of the server
-- We will restove the state afterwards
DECLARE @advopt_old_value int
DECLARE @comp_old_value int
EXECUTE #sp_enable_component 'Agent XPs', @advopt_old_value out, @comp_old_value out
-- sproc that creates a job for PBM. This covers the creation of job for all upgrade scenarios.
PRINT 'Executing msdb.dbo.sp_syspolicy_create_purge_job'
EXEC msdb.dbo.sp_syspolicy_create_purge_job
-- Now restore the Agent XPs to their old state
EXECUTE #sp_restore_component_state 'Agent XPs', @advopt_old_value, @comp_old_value
GO
-- Final upgrade step does not depend on any schema changes, and thus can be run for any upgrade
-- Make sure that the policies are using a valid evaluation mode
-- If a policy is using an evaluation mode that is not supported for a facet, then the evaluation mode is None and it is not enabled
UPDATE p
SET p.execution_mode = 0, p.is_enabled = 0
FROM
[msdb].[dbo].[syspolicy_policies_internal] p
INNER JOIN
[msdb].[dbo].[syspolicy_conditions] c
ON (p.condition_id = c.condition_id)
INNER JOIN
[msdb].[dbo].[syspolicy_management_facets] f
ON (c.facet = f.name)
WHERE p.execution_mode <> (p.execution_mode & f.execution_mode)
-- Upgrade from CTP5 & CTP6 to RC0 - correct typo in the management facet name
UPDATE [msdb].[dbo].[syspolicy_management_facets]
SET name = 'MessageType'
WHERE name = 'Messagetype'
GO
/**************************************************************/
/* End of DMF Post-upgrade steps */
/**************************************************************/
IF (NOT OBJECT_ID(N'tempdb.dbo.#SqlAgentSignatures', 'U') IS NULL)
BEGIN
DROP TABLE #SqlAgentSignatures
END
-------------------------------------------------------------------------
--
/**************************************************************/
/* Data Collector Post-upgrade steps */
/**************************************************************/
GO
-- Procedure to print Data collector status and collection set status
CREATE PROCEDURE #printdatacollectorstatus
AS
BEGIN
DECLARE @parameter_name SYSNAME
DECLARE @parameter_value sql_variant
PRINT 'Data Collector Status'
SELECT @parameter_name = parameter_name, @parameter_value = parameter_value
FROM msdb.dbo.syscollector_config_store_internal
WHERE parameter_name = 'CollectorEnabled'
PRINT @parameter_name + ':' + convert(varchar , @parameter_value)
PRINT 'Collection set status'
DECLARE @collection_set_uid UNIQUEIDENTIFIER
DECLARE @name SYSNAME
DECLARE @is_running BIT
DECLARE @collection_set_cursor CURSOR
SET @collection_set_cursor = CURSOR FOR
SELECT collection_set_uid, name, is_running
FROM msdb.dbo.syscollector_collection_sets_internal
OPEN @collection_set_cursor
FETCH NEXT FROM @collection_set_cursor INTO @collection_set_uid, @name, @is_running
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'Uid:' + convert(varchar(50),@collection_set_uid) + ', Name:' + @name + ', IsRunning:' + convert(varchar, @is_running)
FETCH NEXT FROM @collection_set_cursor INTO @collection_set_uid, @name, @is_running
END
CLOSE @collection_set_cursor
DEALLOCATE @collection_set_cursor
END
GO
-- 'Agent XPs' setting should be turned on if not error is thrown while restoring
-- data collector status
PRINT 'post_dc100::Enabling Agent XPs before restoring data collector original state'
DECLARE @advopt_old_value int
DECLARE @comp_old_value int
EXECUTE #sp_enable_component 'Agent XPs', @advopt_old_value out, @comp_old_value out
EXECUTE #printdatacollectorstatus
-- Load the instmdw.sql script into the blob
PRINT 'post_dc100::uploading instmdw.sql to msdb ...'
EXECUTE [dbo].[sp_syscollector_upload_instmdw]
-- Restore collection set running status
PRINT 'post_dc100::Checking if collection set status were captured in temp table...'
IF (OBJECT_ID('tempdb..#data_collector_collectionset_status', 'U') IS NOT NULL)
BEGIN
PRINT 'post_dc100::Restoring collection set running status...'
UPDATE [dbo].[syscollector_collection_sets_internal]
SET [dbo].[syscollector_collection_sets_internal].is_running = #data_collector_collectionset_status.is_running
FROM #data_collector_collectionset_status
WHERE [dbo].[syscollector_collection_sets_internal].is_running <> #data_collector_collectionset_status.is_running
AND [dbo].[syscollector_collection_sets_internal].collection_set_uid = #data_collector_collectionset_status.collection_set_uid
END
-- Check if temp table that holds data collector's old status before upgrade exists
-- and enable data collector if DC was enabled before running upgrade scripts
PRINT 'post_dc100::Checking if Data collector was enabled before upgrade...'
IF (OBJECT_ID('tempdb..#data_collector_status', 'U') IS NOT NULL)
BEGIN
DECLARE @old_state_enabled_status INT
-- Get the old state of data collector - predicate checks if the old and current state is not the same
-- Expected: @old_state_enabled_status = NULL if old and current states are same
-- @old_state_enabled_status = 0 if old state was disabled and current state is enabled
-- @old_state_enabled_status = 1 if old state was enabled and current state is disabled
SELECT @old_state_enabled_status = oldstatus.data_collector_old_status
FROM [dbo].[syscollector_config_store_internal] cs,
#data_collector_status oldstatus
WHERE cs.parameter_name = 'CollectorEnabled'
AND oldstatus.data_collector_old_status <> CONVERT(int, cs.parameter_value)
-- @old_state_enabled_status is not null only if old and current states are not the same
IF(@old_state_enabled_status IS NOT NULL)
BEGIN
-- If pre-upgrade state was disabled and current state is enabled, Restore to disabled state
IF(@old_state_enabled_status = 0)
BEGIN
PRINT 'post_dc100::Data collector was disabled before upgrade, Restoring Disabled state...'
EXEC sp_syscollector_disable_collector
END
-- If pre-upgrade state was enabled and current state is disables, enabled data collector
ELSE IF(@old_state_enabled_status = 1)
BEGIN
PRINT 'post_dc100::Data collector was enabled before upgrade, Restoring Enabled State ...'
EXEC sp_syscollector_enable_collector
END
ELSE
-- If pre-upgrade state was not 1 or 0, print message ( we should not get into this issue )
BEGIN
PRINT 'post_dc100::Invalid enable/disable state:' + convert(varchar, @old_state_enabled_status)
END
END
ELSE
BEGIN
PRINT 'post_dc100::Current data collector state is same as pre-upgrade state'
END
END
EXECUTE #printdatacollectorstatus
-- Now restore the Agent XPs to their old state
EXECUTE #sp_restore_component_state 'Agent XPs', @advopt_old_value, @comp_old_value
GO
/**************************************************************/
/* End of Data Collector Post-upgrade steps */
/**************************************************************/
DROP PROCEDURE #printdatacollectorstatus
DROP PROCEDURE #sp_enable_component
DROP PROCEDURE #sp_restore_component_state
GO
-------------------------------------------------------------------------
--
/**************************************************************/
/* Utility Post-upgrade steps */
/**************************************************************/
-----------------------------------------------
-- SQL 2008 R2 CTP2 --> CTP3 or later
-----------------------------------------------
-- Drop the CTP2 MI job "sysutility_performance_information_collection" if it exists.
-- This job was renamed in CTP3.
IF EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name = 'sysutility_performance_information_collection')
BEGIN
EXEC msdb.dbo.sp_delete_job @job_name = 'sysutility_performance_information_collection';
END;
GO
/**************************************************************/
/* End of Utility Post-upgrade steps */
/**************************************************************/
/**************************************************************/
/* MSDB Post-upgrade steps */
/**************************************************************/
-- Restoring implicit transactions state
DECLARE @is_implicit_transactions_set BIT
SELECT @is_implicit_transactions_set = CONVERT(BIT, value)
FROM fn_listextendedproperty(N'IMPLICIT_TRANSACTIONS', default, default, default, default, default, default);
IF (@is_implicit_transactions_set IS NOT NULL)
BEGIN
EXEC sp_dropextendedproperty N'IMPLICIT_TRANSACTIONS'
IF @is_implicit_transactions_set = 1
BEGIN
SET IMPLICIT_TRANSACTIONS ON
PRINT 'Restored implicit transactions state to ON'
END
ELSE
BEGIN
SET IMPLICIT_TRANSACTIONS OFF
PRINT 'Restored implicit transactions state to OFF'
END
END
GO
Print 'Upgrading Database Mail related objects...'
/*
One of the main functions of this script is to handle migration
of multiple Mail Host database to a single Mail Host Database in MSDB.
Pre Beta 3 (CPT 15) versions of SQL Server 2005 allowed
Databae Mail object to exist in any database. This script will migrate
previously created profile, SentItems and log information to MSDB.
Finally the script will remove Database Mail objects in these other databases.
Another goal of this script is to handle all metadata changes between different
releases of the product starting with B-2 through subsequent CTPs
*/
USE msdb
SET NOCOUNT ON
-- remove obsolete configuration parameter
IF EXISTS(SELECT * FROM msdb.dbo.sysmail_configuration WHERE paramname = N'MaxNumberOfMailsPerDay')
DELETE FROM msdb.dbo.sysmail_configuration WHERE paramname=N'MaxNumberOfMailsPerDay'
/*
Upgrade objects in MSDB if it was previously used as mailhost database
*/
BEGIN TRY
IF EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='profile_name' and id =
(SELECT OBJECT_ID(N'dbo.sysmail_mailitems', 'U')))
BEGIN
-- convert data from profile_name column to profile_id column
exec sp_executesql N'
DECLARE @profile_name sysname
DECLARE @profile_id int
DECLARE profile_name_cursor CURSOR LOCAL
FOR
SELECT sp.profile_id, sp.name
FROM dbo.sysmail_profile sp, dbo.sysmail_mailitems mi
WHERE sp.name = mi.profile_name AND mi.profile_name IS NOT NULL
OPEN profile_name_cursor
FETCH NEXT FROM profile_name_cursor INTO @profile_id, @profile_name
WHILE (@@fetch_status = 0)
BEGIN
UPDATE dbo.sysmail_mailitems SET profile_id = @profile_id WHERE profile_name = @profile_name
FETCH NEXT FROM profile_name_cursor INTO @profile_id, @profile_name
END
Close profile_name_cursor
DEALLOCATE profile_name_cursor'
-- remove obsolete column
ALTER TABLE dbo.sysmail_mailitems DROP COLUMN profile_name
END
END TRY
BEGIN CATCH
print 'There was a problem upgrading MSDB mail host database.'
print 'Unable to map existing profile name values to profile_id column'
print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
print 'Error Message: ' + ERROR_MESSAGE()
print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER())
print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
END CATCH
GO
if EXISTS(Select * from msdb.dbo.sysmail_principalprofile)
BEGIN
BEGIN TRY
-- add existing mail users defined in MSDB to new role
DECLARE @DBMailUser sysname
DECLARE principal_profile_cursor CURSOR LOCAL FOR
SELECT dp.name FROM dbo.sysmail_principalprofile pp INNER JOIN sys.database_principals dp ON pp.principal_sid = dp.sid and dp.principal_id > 4
OPEN principal_profile_cursor
FETCH NEXT FROM principal_profile_cursor INTO @DBMailUser
WHILE (@@fetch_status = 0)
BEGIN
EXEC msdb..sp_addrolemember @rolename = 'DatabaseMailUserRole',@membername = @DBMailUser
FETCH NEXT FROM principal_profile_cursor INTO @DBMailUser
END
CLOSE principal_profile_cursor
DEALLOCATE principal_profile_cursor
END TRY
BEGIN CATCH
print 'There was a problem upgrading MSDB mail host database.'
print 'Unable to add existing mail user to DatabaseMailUserRole'
print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
print 'Error Message: ' + ERROR_MESSAGE()
print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER())
print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
END CATCH
END
GO
if EXISTS(Select * from msdb.dbo.sysmail_principalprofile)
BEGIN
BEGIN TRY
-- cleaning up database mail related broker conversations
if( SELECT is_broker_enabled from msdb.sys.databases WHERE name = 'msdb' ) = 0
BEGIN
PRINT 'NEED TO RE-ENABLE SSB'
WHILE(1=1)
BEGIN
DECLARE @handle UNIQUEIDENTIFIER
SET @handle = NULL
SELECT TOP(1) @handle=conversation_handle FROM msdb.sys.conversation_endpoints
WHERE (msdb.sys.conversation_endpoints.far_service IN
('SQL/Notifications/SysMailNotification/v1.0',
'ExternalMailService',
'InternalMailService',
'SqlQueryNotificationService',
'iMailRequestorService',
'iMailResponderService',
'http://schemas.microsoft.com/SQL/Notifications/EventNotificationService',
'http://schemas.microsoft.com/SQL/Notifications/PostEventNotification'
)
)
IF @handle IS NULL BREAK
PRINT 'ENDING CONVERSATION ' + convert(varchar(256),@handle)
END CONVERSATION @handle WITH CLEANUP
END
END
-- We cannot turn the broker on, because we don't know whether it was disabled by the user
-- ALTER DATABASE msdb SET ENABLE_BROKER
END TRY
BEGIN CATCH
print 'There was a problem upgrading Mail Host databases.'
print 'Unable to re-enable server broker. You might need to manually'
print 'end any pending secure conversations.'
print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
print 'Error Message: ' + ERROR_MESSAGE()
print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER())
print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
END CATCH
END
GO
if EXISTS(SELECT * FROM msdb.dbo.sysmail_principalprofile) AND
EXISTS(SELECT * FROM msdb.dbo.syscolumns WHERE name='database_id' and id =(SELECT OBJECT_ID(N'dbo.sysmail_principalprofile', 'U')))
BEGIN
/*
Handle migration of multiple mail host databases into MSDB
*/
BEGIN TRY
DECLARE @DBName sysname
DECLARE @DBNameQuote sysname
DECLARE @sql nvarchar(max)
DECLARE @new_mailitem_id int
DECLARE @old_mailitem_id int
DECLARE @profile_name_exists bit
DECLARE @Error bit
DECLARE @db_id int
DECLARE DBName_Cursor CURSOR FOR
select name from sys.databases WHERE name NOT IN ('msdb', 'tempdb', 'master')
and HAS_DBACCESS([name]) <> 0
OPEN DBName_Cursor
FETCH NEXT FROM DBName_Cursor INTO @DBName
WHILE @@FETCH_STATUS = 0
BEGIN
Print 'Checking database: ' + @DBName
SET @DBNameQuote = QUOTENAME(@DBName)
SELECT @db_id = db_id(@DBName)
IF ( OBJECT_ID(@DBNameQuote + '.dbo.sysmail_log') IS NOT NULL) --Determine if Database Mail objects exist
BEGIN
Print @DBName + ' is a MailHost database.'
--Going to migrate profiles from database to MSDB
DECLARE @DBMailUser sysname
DECLARE @sid_MSDB varbinary(85)
DECLARE @sid_principal varbinary(85)
DECLARE @old_profile_id int
DECLARE @new_principal_id int
DECLARE @old_principal_id int
DECLARE @LoginName sysname
SET @sql = N'DECLARE DBMail_Cursor CURSOR FOR
SELECT p.name
, pp.profile_id
, msdb_p.sid
, p.sid
, pp.principal_id
FROM msdb..sysmail_principalprofile pp
JOIN '+ @DBNameQuote +'.sys.database_principals p
ON pp.principal_id = p.principal_id
LEFT JOIN msdb.sys.database_principals msdb_p
ON p.sid = msdb_p.sid
where pp.database_id = ' + convert(nvarchar(10),@db_id)
--print @sql
EXEC(@sql)
OPEN DBMail_Cursor
FETCH NEXT FROM DBMail_Cursor INTO @DBMailUser, @old_profile_id, @sid_MSDB, @sid_principal, @old_principal_id
WHILE @@FETCH_STATUS = 0
BEGIN
Print 'Going to process user: ' + @DBMailUser
IF (@sid_MSDB IS NULL) -- does not already exist in MSDB
BEGIN
IF (NOT EXISTS(Select * from sysusers where name = @DBMailUser))
BEGIN
IF (EXISTS(Select * from master.dbo.syslogins where sid = @sid_principal))
BEGIN
/* Determine the Login Name from the SID */
SELECT @LoginName = name
FROM master.dbo.syslogins
WHERE sid = @sid_principal
PRINT 'Add USER to MSDB: ' + @DBMailUser
SET @sql = N'CREATE USER ' + QUOTENAME(@DBMailUser) + ' FOR LOGIN ' + QUOTENAME(@LoginName)
EXEC (@sql)
IF (@old_principal_id > 4) -- do not add special accounts such as dbo, public, sys
BEGIN
Print 'Grant USER permission to send mail.'
exec msdb..sp_addrolemember @rolename = 'DatabaseMailUserRole',@membername = @DBMailUser
END
END
ELSE
BEGIN
PRINT 'Can not add user as the login does not exist.'
END
END
ELSE
BEGIN
Print 'User has already been added to MSDB: ' + @DBMailUser
IF (@old_principal_id > 4) -- do not add special accounts such as dbo, public, sys
BEGIN
PRINT 'Ensure user has the right to send mail.'
exec msdb..sp_addrolemember @rolename = 'DatabaseMailUserRole',@membername = @DBMailUser
END
END
END
ELSE
BEGIN
Print 'Login already mapped to a user in MSDB'
END
IF (EXISTS(Select * from master.dbo.syslogins where sid = @sid_principal))
BEGIN
--Get principle_id
SELECT @new_principal_id = principal_id
FROM msdb.sys.database_principals
Where sid = @sid_principal
IF (@new_principal_id is not Null)
BEGIN
print 'New Principal_id: ' + Convert(varchar(10),@new_principal_id) + ' Old profile_id: ' + convert(varchar(10),@old_profile_id) + ' Old principal id: ' + convert(varchar(10),@old_principal_id)
SET @sql = N'
IF NOT EXISTS(select * from msdb..sysmail_principalprofile
Where profile_id = ' + Convert(varchar(10),@old_profile_id) + '
AND database_id = 4
AND principal_id = ' + Convert(varchar(10),@new_principal_id) + ')
BEGIN
--Update the Profile
UPDATE msdb..sysmail_principalprofile
SET database_id = 4
, principal_id = ' + Convert(varchar(10),@new_principal_id) + '
Where profile_id = ' + Convert(varchar(10),@old_profile_id) + '
AND database_id = ' + Convert(varchar(10),@db_id) + '
AND principal_id = ' + Convert(varchar(10),@old_principal_id) + '
IF (@@rowcount = 1)
BEGIN
Print ''sysmail_principalprofile updated based on moving user to MSDB.''
END
END
ELSE
BEGIN
Print ''This user already has already been configured with this profile in MSDB.''
END'
EXEC(@sql)
END
ELSE
BEGIN
Print 'sysmail_principalprofile table can not be updated for sid: ' + convert(varchar(100),@sid_principal)
END
END
FETCH NEXT FROM DBMail_Cursor INTO @DBMailUser, @old_profile_id, @sid_MSDB, @sid_principal, @old_principal_id
END
CLOSE DBMail_Cursor
DEALLOCATE DBMail_Cursor
--/* Move Data from user Mail Host database to MSDB */
--Print 'Move Data from user Mail Host database to MSDB.'
SET @sql = N'DECLARE mailitem_id_Cursor CURSOR FOR
SELECT mailitem_id FROM ' + @DBNameQuote + '.dbo.sysmail_mailitems'
EXEC(@sql)
OPEN mailitem_id_Cursor
Set @Error = 0 --Assume no errors
BEGIN TRANSACTION
/* Disable Trigger so the "last_mod_date" and "last_mod_user colums" are not updated during transfer. */
EXEC ('DISABLE TRIGGER [dbo].[trig_sysmail_attachments] ON [dbo].[sysmail_attachments]')
EXEC ('DISABLE TRIGGER [dbo].[trig_sysmail_log] ON [dbo].[sysmail_log]')
EXEC ('DISABLE TRIGGER [dbo].[trig_sysmail_mailitems]ON [dbo].[sysmail_mailitems]')
Print 'Going to move ALL sysmail_log items not associated with a mailitem'
SET @sql = N'INSERT INTO msdb.dbo.sysmail_log
(event_type, log_date, description, process_id, mailitem_id, account_id, last_mod_date, last_mod_user)
SELECT event_type, log_date, description, process_id, NULL, account_id, last_mod_date, last_mod_user
FROM '+ @DBNameQuote +'.dbo.sysmail_log
WHERE mailitem_id IS NULL '
exec(@sql)
FETCH NEXT FROM mailitem_id_Cursor INTO @old_mailitem_id
WHILE @@FETCH_STATUS = 0
BEGIN
/****************************************/
/* MOVE dbo.sysmail_mailitems DATA */
/****************************************/
/* Need to check the schema defination of the table */
SET @sql = N'USE ' + @DBNameQuote + '
DECLARE @sql nvarchar(max)
IF (EXISTS(select * from syscolumns
where id = object_id(''[dbo].[sysmail_mailitems]'')
AND name = ''profile_name''))
BEGIN
SET @sql = N''INSERT INTO msdb.dbo.sysmail_mailitems
(profile_id, recipients, copy_recipients, blind_copy_recipients, subject, body, body_format, importance, sensitivity, file_attachments, attachment_encoding, query, execute_query_database, attach_query_result_as_file, query_result_header, query_result_width, query_result_separator, exclude_query_output, append_query_error, send_request_date, send_request_user, sent_account_id, sent_status, sent_date, last_mod_date, last_mod_user)
SELECT CASE WHEN p.profile_id IS NULL THEN -1 ELSE p.profile_id END, recipients, copy_recipients, blind_copy_recipients, subject, body, body_format, importance, sensitivity, file_attachments, attachment_encoding, query, execute_query_database, attach_query_result_as_file, query_result_header, query_result_width, query_result_separator, exclude_query_output, append_query_error, send_request_date, send_request_user, sent_account_id, sent_status, sent_date, last_mod_date, mi.last_mod_user
FROM '+ @DBNameQuote +'.dbo.sysmail_mailitems mi LEFT JOIN msdb..sysmail_profile p
ON mi.profile_name = p.name
WHERE mailitem_id = ' + CONVERT(VARCHAR(20),@old_mailitem_id) + '''
END
ELSE
BEGIN
SET @sql = N''INSERT INTO msdb.dbo.sysmail_mailitems
(profile_id, recipients, copy_recipients, blind_copy_recipients, subject, body, body_format, importance, sensitivity, file_attachments, attachment_encoding, query, execute_query_database, attach_query_result_as_file, query_result_header, query_result_width, query_result_separator, exclude_query_output, append_query_error, send_request_date, send_request_user, sent_account_id, sent_status, sent_date, last_mod_date, last_mod_user)
SELECT profile_id, recipients, copy_recipients, blind_copy_recipients, subject, body, body_format, importance, sensitivity, file_attachments, attachment_encoding, query, execute_query_database, attach_query_result_as_file, query_result_header, query_result_width, query_result_separator, exclude_query_output, append_query_error, send_request_date, send_request_user, sent_account_id, sent_status, sent_date, last_mod_date, last_mod_user
FROM '+ @DBNameQuote +'.dbo.sysmail_mailitems
WHERE mailitem_id = ' + CONVERT(VARCHAR(20),@old_mailitem_id) + '''
END
EXEC(@sql)'
EXEC(@sql)
IF (@@error <> 0) --Check for error
BEGIN
Set @Error = 1
END
SELECT @new_mailitem_id = @@identity
/****************************************/
/* MOVE dbo.sysmail_log DATA */
/****************************************/
SET @sql = N'INSERT INTO msdb.dbo.sysmail_log
(event_type, log_date, description, process_id, mailitem_id, account_id, last_mod_date, last_mod_user)
SELECT event_type, log_date, description, process_id, ' + convert(varchar(5),@new_mailitem_id) + ', account_id, last_mod_date, last_mod_user
FROM '+ @DBNameQuote +'.dbo.sysmail_log
WHERE mailitem_id = ' + CONVERT(VARCHAR(20),@old_mailitem_id)
EXEC(@sql)
IF @@error <> 0 --Check for error
BEGIN
Set @Error = 1
END
/****************************************/
/* MOVE dbo.sysmail_attachments DATA */
/****************************************/
SET @sql = N'USE ' + @DBNameQuote + '
IF (object_id(''dbo.sysmail_attachments'') IS NOT NULL)
begin
INSERT INTO msdb.dbo.sysmail_attachments
(mailitem_id, filename, filesize, attachment, last_mod_date, last_mod_user)
SELECT ' + convert(varchar(5),@new_mailitem_id) + ', filename, filesize, attachment, last_mod_date, last_mod_user
FROM '+ @DBNameQuote +'.dbo.sysmail_attachments
WHERE mailitem_id = ' + CONVERT(VARCHAR(20),@old_mailitem_id) + '
end'
EXEC(@sql)
IF @@error <> 0 --Check for error
BEGIN
Set @Error = 1
END
FETCH NEXT FROM mailitem_id_Cursor INTO @old_mailitem_id
END
IF @Error = 0
BEGIN
Print 'Completed data transfer to MSDB.'
COMMIT TRANSACTION
END
ELSE
BEGIN
Print 'Not able to complete data transfer to MSDB.'
ROLLBACK TRANSACTION
END
/* ENABLE Triggers as they were previously DISABLE */
EXEC ('ENABLE TRIGGER [dbo].[trig_sysmail_attachments] ON [dbo].[sysmail_attachments]')
EXEC ('ENABLE TRIGGER [dbo].[trig_sysmail_log] ON [dbo].[sysmail_log]')
EXEC ('ENABLE TRIGGER [dbo].[trig_sysmail_mailitems]ON [dbo].[sysmail_mailitems]')
CLOSE mailitem_id_Cursor
DEALLOCATE mailitem_id_Cursor
IF @Error = 0
BEGIN
/**********************************************************************/
/* */
/* Uninstalls the tables, triggers and stored procedures necessary for*/
/* sqlimail operations */
/* */
/*
** Copyright (c) Microsoft Corporation
** All Rights Reserved.
*/
/**********************************************************************/
/**************************************************************/
-- Drop ALL Database Mail objects (i.e Functions/Procedures )
/**************************************************************/
PRINT ''
PRINT 'Dropping old Database Mail FUNCTIONS and PROCEDURES ...'
PRINT ''
-----
PRINT 'Dropping function ConvertToInt'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.ConvertToInt'', ''FN'') IS NULL
DROP FUNCTION ConvertToInt')
-----
PRINT 'Dropping procedure sysmail_start_sp'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_start_sp'', ''P'') IS NULL
DROP PROCEDURE dbo.sysmail_start_sp')
-----
PRINT 'Dropping procedure sysmail_stop_sp'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_stop_sp'', ''P'') IS NULL
DROP PROCEDURE dbo.sysmail_stop_sp')
-----
PRINT 'Dropping procedure sysmail_logmailevent_sp'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_logmailevent_sp'', ''P'') IS NULL
DROP PROCEDURE dbo.sysmail_logmailevent_sp')
-----
PRINT 'Dropping procedure sp_has_changedbuser_permission'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_has_changedbuser_permission'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_has_changedbuser_permission')
-----
PRINT 'Dropping procedure sp_getprofilerequestxml'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_getprofilerequestxml'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_getprofilerequestxml')
-----
PRINT 'Dropping procedure sp_sendandreturn'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_sendandreturn'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_sendandreturn')
-----
PRINT 'Dropping procedure sp_sendandblock'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_sendandblock'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_sendandblock')
-----
PRINT 'Dropping procedure sp_isprohibited'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_isprohibited'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_isprohibited')
-----
PRINT 'Dropping procedure sp_sendimailqueues'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_sendimailqueues'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_sendimailqueues')
-----
PRINT 'Dropping procedure sp_gettestprofilexml'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_gettestprofilexml'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_gettestprofilexml')
-----
PRINT 'Dropping procedure sp_testprofileimailqueues'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_testprofileimailqueues'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_testprofileimailqueues')
-----
PRINT 'Dropping procedure sp_endconversation'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_endconversation'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_endconversation')
-----
PRINT 'Dropping procedure sp_endconversation'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_endconversation'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_endconversation')
-----
PRINT 'Dropping procedure sp_readrequest'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_readrequest'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_readrequest')
-----
PRINT 'Dropping procedure sp_sendresponse'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_sendresponse'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_sendresponse')
-----
PRINT 'Dropping procedure sp_sendtestprofileresponse'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_sendtestprofileresponse'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_sendtestprofileresponse')
-----
PRINT 'Dropping procedure sp_getsendmailxml'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_getsendmailxml'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_getsendmailxml')
-----
PRINT 'Dropping procedure sendimail_sp'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sendimail_sp'', ''P'') IS NULL
DROP PROCEDURE dbo.sendimail_sp')
-----
PRINT 'Dropping procedure sp_testimailprofile'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_testimailprofile'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_testimailprofile')
-----
PRINT 'Dropping procedure dbo.sp_add_quota_information'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_add_quota_information'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_add_quota_information')
-----
PRINT 'Dropping procedure dbo.sp_current_principal_mails'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_current_principal_mails'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_current_principal_mails')
-----
PRINT 'Dropping procedure dbo.sp_delete_quota_information'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_delete_quota_information'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_delete_quota_information')
-----
PRINT 'Dropping procedure dbo.sp_ExernalMailQueueListener'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_ExernalMailQueueListener'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_ExernalMailQueueListener')
-----
PRINT 'Dropping procedure dbo.sp_GetAttachmentData'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_GetAttachmentData'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_GetAttachmentData')
-----
PRINT 'Dropping procedure dbo.sp_RunMailQuery'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_RunMailQuery'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_RunMailQuery')
-----
PRINT 'Dropping procedure dbo.sp_SendMailMessage'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_SendMailMessage'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_SendMailMessage')
-----
PRINT 'Dropping procedure dbo.sp_SendMailQueues'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_SendMailQueues'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_SendMailQueues')
-----
PRINT 'Dropping procedure dbo.sp_verify_quota_mail_count'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_verify_quota_mail_count'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_verify_quota_mail_count')
-----
PRINT 'Dropping procedure dbo.sp_activate_sqlimail'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_activate_sqlimail'', ''P'') IS NULL
DROP PROCEDURE dbo.sp_activate_sqlimail')
/**************************************************************/
-- Drop all Database Mail TABLES
/**************************************************************/
PRINT ''
PRINT 'Dropping TABLES...'
PRINT ''
-----
PRINT 'Dropping table sysmail_log'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_log'', ''U'') IS NULL
DROP TABLE sysmail_log')
-----
PRINT 'Dropping table sysmail_send_retries'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_send_retries'', ''U'') IS NULL
DROP TABLE dbo.sysmail_send_retries')
-----
PRINT 'Dropping table sqlimail_data_transfer'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sqlimail_data_transfer'', ''U'') IS NULL
DROP TABLE sqlimail_data_transfer')
-----
PRINT 'Dropping table sysmail_attachments'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_attachments'', ''U'') IS NULL
DROP TABLE sysmail_attachments')
-----
PRINT 'Dropping table sysmail_query_transfer'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_query_transfer'', ''U'') IS NULL
DROP TABLE sysmail_query_transfer')
-----
PRINT 'Dropping table sysmail_attachments_transfer'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_attachments_transfer'', ''U'') IS NULL
DROP TABLE sysmail_attachments_transfer')
-----
PRINT 'Dropping table sysmail_quota_information'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_quota_information'', ''U'') IS NULL
DROP TABLE sysmail_quota_information')
-----
PRINT 'Dropping table sysmail_mailitems'
-----
EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_mailitems'', ''U'') IS NULL
DROP TABLE sysmail_mailitems')
/**************************************************************/
-- Drop MESSAGES, CONTRACTS, QUEUES AND SERVICES
/**************************************************************/
PRINT ''
PRINT 'Dropping MESSAGES, CONTRACTS, QUEUES AND SERVICES...'
PRINT ''
-----
PRINT 'Dropping service iMailRequestorService'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.services WHERE name =''iMailRequestorService'')
DROP SERVICE iMailRequestorService')
-----
PRINT 'Dropping service iMailResponderService'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.services WHERE name =''iMailResponderService'')
DROP SERVICE iMailResponderService')
-----
PRINT 'Dropping queue iMailRequestor'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.objects WHERE name = ''iMailRequestor'' AND type = ''SQ'')
DROP QUEUE iMailRequestor')
-----
PRINT 'Dropping queue iMailResponder'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.objects WHERE name = ''iMailResponder'' AND type = ''SQ'')
DROP QUEUE iMailResponder')
-----
PRINT 'Dropping service [SQL/Notifications/IMailNotification/v1.0]'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.services WHERE name =''SQL/Notifications/IMailNotification/v1.0'')
DROP SERVICE [SQL/Notifications/IMailNotification/v1.0]')
-----
PRINT 'Dropping service [ExternalMailService]'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.services WHERE name =''ExternalMailService'')
DROP SERVICE [ExternalMailService]')
-----
PRINT 'Dropping service [InternalMailService]'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.services WHERE name =''InternalMailService'')
DROP SERVICE [InternalMailService]')
-----
PRINT 'Dropping queue iMailNotificationQueue'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.objects WHERE name = ''iMailNotificationQueue'' AND type = ''SQ'')
DROP QUEUE iMailNotificationQueue')
-----
PRINT 'Dropping contract [//www.microsoft.com/imail/contracts/SendMail/v1.0]'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS(SELECT * FROM sys.service_contracts
WHERE name = ''//www.microsoft.com/imail/contracts/SendMail/v1.0'')
DROP CONTRACT [//www.microsoft.com/imail/contracts/SendMail/v1.0]')
-----
PRINT 'Dropping message type [{//www.microsoft.com/imail/messages}SendMail]'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS(SELECT * FROM sys.service_message_types
WHERE name = ''{//www.microsoft.com/imail/messages}SendMail'')
DROP MESSAGE TYPE [{//www.microsoft.com/imail/messages}SendMail]')
-----
PRINT 'Dropping contract [//www.microsoft.com/imail/contracts/TestProfile/v1.0]'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS(SELECT * FROM sys.service_contracts
WHERE name = ''//www.microsoft.com/imail/contracts/TestProfile/v1.0'')
DROP CONTRACT [//www.microsoft.com/imail/contracts/TestProfile/v1.0]')
-----
PRINT 'Dropping message type [{//www.microsoft.com/imail/messages}TestProfile]'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS(SELECT * FROM sys.service_message_types
WHERE name = ''{//www.microsoft.com/imail/messages}TestProfile'')
DROP MESSAGE TYPE [{//www.microsoft.com/imail/messages}TestProfile]')
-----
PRINT 'Dropping message type [{//www.microsoft.com/imail/messages}TestProfileResponse]'
-----
EXEC('USE ' + @DBNameQuote + ' IF EXISTS(SELECT * FROM sys.service_message_types
WHERE name = ''{//www.microsoft.com/imail/messages}TestProfileResponse'')
DROP MESSAGE TYPE [{//www.microsoft.com/imail/messages}TestProfileResponse]')
-----
PRINT 'Dropping certificates and related users'
-----
DECLARE @sqlcmd nvarchar(max),
@CertName sysname,
@CertNameQuoted sysname,
@MailLogin sysname,
@MailLoginQuoted sysname
SELECT @CertName = N'SQLiMail-Certificate-' + @DBName,
@CertNameQuoted = QUOTENAME( @CertName,''''),
@MailLogin = N'SQLiMail-' + @DBName + '-Certificate-Login',
@MailLoginQuoted= QUOTENAME( @MailLogin,'''')
-----
PRINT 'Dropping user in msdb'
-----
SET @sqlcmd =
N'USE msdb
IF(EXISTS (SELECT * FROM sys.database_principals WHERE name = N' + @MailLoginQuoted + '))
DROP USER ' + QUOTENAME( @MailLogin)
EXEC sp_executesql @sqlcmd
-----
PRINT 'Dropping user and certificate login in master'
-----
SET @sqlcmd =
N'USE master
IF(EXISTS (SELECT * FROM sys.database_principals WHERE name = N' + @MailLoginQuoted + '))
DROP USER ' + QUOTENAME( @MailLogin) + '
IF(EXISTS(select * from sys.server_principals where name = N' + @MailLoginQuoted + '))
DROP LOGIN ' + QUOTENAME( @MailLogin)
EXEC sp_executesql @sqlcmd
-----
PRINT 'Dropping user in this database'
-----
SET @sqlcmd =
N'USE ' + @DBNameQuote + '
IF(EXISTS (SELECT * FROM sys.database_principals WHERE name = N' + @MailLoginQuoted + '))
DROP USER ' + QUOTENAME( @MailLogin)
EXEC sp_executesql @sqlcmd
-----
PRINT 'Dropping the certificate in this db'
-----
SET @sqlcmd =
N'USE ' + @DBNameQuote + '
IF(EXISTS(SELECT * FROM sys.certificates WHERE name = N' + @CertNameQuoted + '))
BEGIN
DROP CERTIFICATE ' + QUOTENAME(@CertName) + '
END'
EXEC sp_executesql @sqlcmd
-----
PRINT 'Dropping certificate from master'
-----
SET @sqlcmd =
N'USE master
IF(EXISTS(SELECT * FROM sys.certificates WHERE name = N' + @CertNameQuoted + '))
DROP CERTIFICATE ' + QUOTENAME(@CertName)
EXEC sp_executesql @sqlcmd
END
END
FETCH NEXT FROM DBName_Cursor INTO @DBName
END -- Loop through all databases.
CLOSE DBName_Cursor
DEALLOCATE DBName_Cursor
-- deleting all principal associations that are not in MSDB or public
exec sp_executesql N'
delete from msdb.dbo.sysmail_principalprofile
where database_id <> 4 and database_id <> 0'
END TRY
BEGIN CATCH
print 'There was a problem upgrading Mail Host databases.'
print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
print 'Error Message: ' + ERROR_MESSAGE()
print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER())
print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
END CATCH
END
BEGIN TRY
IF EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='principal_id' and id =
(SELECT OBJECT_ID(N'dbo.sysmail_principalprofile', 'U')))
BEGIN
-- convert data from principal_id to principal_sid
exec sp_executesql N'
DECLARE @principal_sid varbinary(85)
DECLARE @principal_id int
DECLARE principal_sid_cursor CURSOR LOCAL
FOR
SELECT distinct principal_id
FROM dbo.sysmail_principalprofile
OPEN principal_sid_cursor
FETCH NEXT FROM principal_sid_cursor INTO @principal_id
WHILE (@@fetch_status = 0)
BEGIN
IF @principal_id = 0
SET @principal_sid = 0x00
ELSE
SELECT @principal_sid = dbo.get_principal_sid(@principal_id)
IF @principal_sid IS NOT NULL -- principal_id is valid
BEGIN
UPDATE dbo.sysmail_principalprofile
SET principal_sid = @principal_sid
WHERE principal_id = @principal_id
END
ELSE
BEGIN
DELETE FROM dbo.sysmail_principalprofile
WHERE principal_id = @principal_id
END
FETCH NEXT FROM principal_sid_cursor INTO @principal_id
END
CLOSE principal_sid_cursor
DEALLOCATE principal_sid_cursor'
-- safety clean-up
DELETE FROM dbo.sysmail_principalprofile WHERE principal_sid = 0xFFFF
-- remove obsolete column
ALTER TABLE dbo.sysmail_principalprofile DROP CONSTRAINT [SYSMAIL_PRINCIPALPROFILE_ProfilePrincipalMustBeUnique]
ALTER TABLE dbo.sysmail_principalprofile DROP COLUMN principal_id
ALTER TABLE dbo.sysmail_principalprofile ADD CONSTRAINT [SYSMAIL_PRINCIPALPROFILE_ProfilePrincipalMustBeUnique] PRIMARY KEY CLUSTERED ([profile_id] ASC,[principal_sid] ASC)
END
END TRY
BEGIN CATCH
print 'There was a problem upgrading MSDB mail host database.'
print 'Unable to map existing profile id values to profile_sid column'
print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
print 'Error Message: ' + ERROR_MESSAGE()
print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER())
print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
END CATCH
GO
BEGIN TRY
-- remove database_id column
IF EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='database_id' and id =
(SELECT OBJECT_ID(N'dbo.sysmail_principalprofile', 'U')))
BEGIN
ALTER TABLE dbo.sysmail_principalprofile DROP CONSTRAINT [SYSMAIL_PRINCIPALPROFILE_ProfilePrincipalMustBeUnique]
ALTER TABLE dbo.sysmail_principalprofile DROP COLUMN database_id
ALTER TABLE dbo.sysmail_principalprofile ADD CONSTRAINT [SYSMAIL_PRINCIPALPROFILE_ProfilePrincipalMustBeUnique] PRIMARY KEY CLUSTERED ([profile_id] ASC,[principal_sid] ASC)
END
END TRY
BEGIN CATCH
print 'There was a problem upgrading MSDB mail host database.'
print 'Unable to create a primary key constraint on sysmail_principalprofile table'
print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
print 'Error Message: ' + ERROR_MESSAGE()
print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER())
print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
END CATCH
Print 'Completed upgrade of Database Mail related objects...'
GO