diff --git a/CommandExecute.sql b/CommandExecute.sql index 81dad9b2..c4d5b6d8 100644 --- a/CommandExecute.sql +++ b/CommandExecute.sql @@ -36,7 +36,10 @@ BEGIN --// Source: https://ola.hallengren.com //-- --// License: https://ola.hallengren.com/license.html //-- --// GitHub: https://github.com/olahallengren/sql-server-maintenance-solution //-- - --// Version: 2024-12-27 18:10:28 //-- + --// Version: 2025-02-19 21:12:35 //-- + --// //-- + --// Forked Changes https://github.com/amazon-contributing/aws-sql-server-maintenance-solution //-- + --// Version: 2024-12-30 12:58 //-- ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON @@ -70,14 +73,36 @@ BEGIN DECLARE @RevertCommand nvarchar(max) + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + DECLARE @AmazonRDS bit = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END + DECLARE @task_id INT + + DECLARE @RDSQueue TABLE ([task_id] INT, + [task_type] nvarchar(max), + [database_name] nvarchar(max), + [% complete] nvarchar(max), + [duration (mins)] nvarchar(max), + [lifecycle] nvarchar(max), + [task_info] nvarchar(max), + [last_updated] nvarchar(max), + [created_at] nvarchar(max), + [S3_object_arn] nvarchar(max), + [overwrite_s3_backup_file] nvarchar(max), + [KMS_master_key_arn] nvarchar(max), + [filepath] nvarchar(max), + [overwrite_file] BIT) + ---------------------------------------------------------------------------------------------------- + ---------------------------------------------------------------------------------------------------- --// Check core requirements //-- ---------------------------------------------------------------------------------------------------- - IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE database_id = DB_ID()) >= 90 + IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE [name] = DB_NAME()) >= 90 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The database ' + QUOTENAME(DB_NAME(DB_ID())) + ' has to be in compatibility level 90 or higher.', 16, 1 + SELECT 'The database ' + QUOTENAME(DB_NAME()) + ' has to be in compatibility level 90 or higher.', 16, 1 END IF NOT (SELECT uses_ansi_nulls FROM sys.sql_modules WHERE [object_id] = @@PROCID) = 1 @@ -224,9 +249,41 @@ BEGIN IF @Mode = 1 AND @Execute = 'Y' BEGIN - EXECUTE @sp_executesql @stmt = @Command - SET @Error = @@ERROR - SET @ReturnCode = @Error + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @AmazonRDS = 1 + BEGIN + BEGIN TRY + EXECUTE @sp_executesql @stmt = @Command + INSERT INTO @RDSQueue exec msdb..rds_task_status @db_name=@DatabaseName; + SELECT TOP 1 @task_id=task_id from @RDSQueue ORDER BY task_id DESC + INSERT INTO dbo.RDS_BackupLog (ID, task_id, [Status]) VALUES (@ID, @task_id, 'CREATED') + END TRY + BEGIN CATCH + SET @Error = ERROR_NUMBER() + SET @ErrorMessageOriginal = ERROR_MESSAGE() + BEGIN + SET @ErrorMessage = 'RDS:Msg ' + CAST(ERROR_NUMBER() AS nvarchar) + ', ' + ISNULL(ERROR_MESSAGE(),'') + + SET @Severity = CASE WHEN ERROR_NUMBER() IN(1205,1222) THEN @LockMessageSeverity ELSE 16 END + IF @ErrorMessageOriginal NOT LIKE 'A task has already been issued for database: %' + RAISERROR('%s',@Severity,1,@ErrorMessage) WITH LOG + ELSE + BEGIN + SET @ErrorMessage = 'RDS:Msg ' + CAST(ERROR_NUMBER() AS nvarchar) + ', ' + ISNULL(ERROR_MESSAGE(),'') + RAISERROR('%s',@Severity,1,@ErrorMessage) WITH NOWAIT + END + END + END CATCH + END + ELSE + BEGIN + EXECUTE @sp_executesql @stmt = @Command + SET @Error = @@ERROR + SET @ReturnCode = @Error + END + ---------------------------------------------------------------------------------------------------- END IF @Mode = 2 AND @Execute = 'Y' @@ -290,4 +347,3 @@ BEGIN END GO - diff --git a/CreateRdsbackupMonitoring.ps1 b/CreateRdsbackupMonitoring.ps1 new file mode 100644 index 00000000..8000db89 --- /dev/null +++ b/CreateRdsbackupMonitoring.ps1 @@ -0,0 +1,205 @@ +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of this +# software and associated documentation files (the "Software"), to deal in the Software +# without restriction, including without limitation the rights to use, copy, modify, +# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +<# + .SYNOPSIS + CreateRdsbackupMonitoring.ps1 + + .DESCRIPTION + This script configures RDS instances to export their Error Logs into CloudWatch, then configures a Metric and Alarm to report SQL Server backup Errors + You can run for all RDS instances in all regions or filter for a subset of regions and RDS instances + .EXAMPLE + To run for All regions and All RDS instances: + .\CreateRdsbackupMonitoring.ps1 -SnsTopic 'arn:aws:sns:xxxxx:0000000000:MySNSTopic' + + To filter for a subset of regions: + .\CreateRdsbackupMonitoring.ps1 -regions 'us-east-1,us-east-2' -SnsTopic 'arn:aws:sns:xxxxx:0000000000:MySNSTopic' + + To run for a subset of RDS Instances + .\CreateRdsbackupMonitoring.ps1 -regions 'us-east-1' -SnsTopic 'arn:aws:sns:xxxxx:0000000000:MySNSTopic' -RdsInstances 'sql-1,sql-2' + + To run for a single RDS Instances + .\CreateRdsbackupMonitoring.ps1 -regions 'us-east-1' -SnsTopic 'arn:aws:sns:xxxxx:0000000000:MySNSTopic' -RdsInstances 'sql-1' + + .NOTES + Date: 01/02/2025 + + .AUTHOR + Phil Ekins - ekins@amazon.com +#> + +Param ( + [Parameter(Mandatory=$true)] [string] $SnsTopicARN, + [Parameter(Mandatory=$false)] [String] $Regions, + [Parameter(Mandatory=$false)] [string] $RdsInstances +) + +#================================================== +# Variables +#================================================== + +$Namespace = "AWS-RDS-Backup-Errors" +$AlarmDescription = "Alarm when RDS Backup Error Detected" +$LogFilterName = "AWS-RDS-Backup-Filter" +$LogFilterPattern = "Errors Detected in RDS Backup Queue Status" + +#================================================== +# Functions +#================================================== + +Function IsvalidRegion { + [CmdletBinding()] + param ( + [String]$Region + ) + + Try { + IF (([string]::IsNullOrWhiteSpace($Region))) { + $IsvalidRegion = $false + } Else { + IF ((Get-AWSRegion -SystemName $Region -IncludeChina -IncludeGovCloud).Name -ne 'Unknown') { + $AccountNumber = $Null + $AccountNumber = Get-STSCallerIdentity -Region $Region -ErrorAction Stop | Select-Object -ExpandProperty 'Account' + $IsvalidRegion = $true + } Else { + $IsvalidRegion = $false + } + } + } Catch { + $IsvalidRegion = $false + } + Return $IsvalidRegion +} + +#================================================== +# Main +#================================================== + +IF (!([string]::IsNullOrWhiteSpace($SnsTopicARN))) { + Try { + $SnsTopic = Get-SNSTopicAttribute -TopicArn $SnsTopicARN -ErrorAction Stop + } Catch { + Write-Host "Invalid SNS Topic." + Exit + } +} Else { + Write-Host "Invalid SNS Topic." + Exit +} + +Try { + IF ([string]::IsNullOrWhiteSpace($Regions)) { + [string[]]$regions = Get-AWSRegion -IncludeChina -IncludeGovCloud -ErrorAction Stop | Where-Object { $_.Region -notlike '*-iso*' } | Select-Object -ExpandProperty 'Region' + $RegionsManuallyEntered = $false + } Else { + [string[]]$regions = $Regions.split(',') + $RegionsManuallyEntered = $true + } +} Catch [System.Exception] { + Write-Host "Failed to get Regions." + Exit +} + +ForEach ($region in $regions) { + IF (IsValidRegion $region) { + write-host "Processing: $region" + Try { + IF (!([string]::IsNullOrWhiteSpace($RdsInstances))) { + [string[]]$RdsInstances = $RdsInstances.split(',') + } Else { + [string[]]$rdsInstances = Get-RDSDBInstance -Region $region -Select DBInstances.DBInstanceIdentifier -ErrorAction Stop + } + + ForEach ($rds in $rdsInstances) { + + Write-host "Processing RDS Instance:"$rds + + $MetricName = "AWS-RDS-Backup-Metric-$rds" + $AlarmName = "AWS-RDS-Backup-Alarm-$rds" + $LogName = "/aws/rds/instance/$rds/error" + + Try { + $RdsInstanceInfo = Get-RDSDBInstance -DBInstanceIdentifier $rds -region $region -ErrorAction Stop + + IF ($RdsInstanceInfo.DBInstanceStatus -eq 'available') { + Try { + $output = Edit-RDSDBInstance -DBInstanceIdentifier $rds -CloudwatchLogsExportConfiguration_EnableLogType 'error' -ApplyImmediately $true -Region $region -ErrorAction Stop + Write-Host " - Log Export (errorlog) to CloudWatch Enabled on $rds" + } Catch { + Write-Host "Errors Occured Setting Error Log Export on $rds." + Exit + } + + Try { + IF ((Get-CWLLogGroup -LogGroupNamePattern $LogName -Region $region -ErrorAction Stop) -eq $null) { + $counter = 0 + While ( ((Get-CWLLogGroup -LogGroupNamePattern $LogName -Region $region -ErrorAction Stop) -eq $null) -AND ($counter -ge 1) ) { + Write-Host "Pausing 60 seconds for log group creation : $rds" + Start-sleep 60 + $counter ++ + } + } + } Catch { + Write-Host "Errors Occured Checking Error Log Export State on $rds." + Exit + } + + IF ((Get-CWLLogGroup -LogGroupNamePattern $LogName -Region $region -ErrorAction Stop) -eq $null) { + Write-Host "Skipping $rds, Error Log group has not been published to CloudWatch yet, re-run for $rds after error log group is created." + } Else { + Try { + $metricTransformation = @{ + MetricName = $MetricName + MetricNamespace = $Namespace + MetricValue = "1" + } + Write-CWLMetricFilter -LogGroupName $LogName -FilterName $LogFilterName -FilterPattern $LogFilterPattern -MetricTransformation $metricTransformation -region $region -ErrorAction Stop + Write-Host " - Metric Filter $LogFilterName Created on $rds" + } Catch { + Write-Host "Errors Occured Creating Metric Filter on $rds." + Exit + } + + Try { + Write-CWMetricAlarm -AlarmName $AlarmName -AlarmDescription $AlarmDescription -MetricName $MetricName -Namespace $Namespace -Statistic Minimum -Period 60 -Threshold 0 -ComparisonOperator GreaterThanThreshold -EvaluationPeriod 1 -AlarmAction $SnsTopicARN -DatapointsToAlarm 1 -TreatMissingData "notBreaching" -region $region -ErrorAction Stop + Write-Host " - Metric Alarm $AlarmName Created on $rds" + } Catch { + Write-Host "Errors Occured Creating Metric Filter Alarm on $rds." + Exit + } + } + } Else { + Write-Host " - RDS instance $rds is not available for modifications." + } + } Catch { + Write-Host "RDS instance $rds not found in region $region." + } + } + } Catch [System.Exception] { + Write-host "Skipping: $region" + $error.Clear() + } + $RdsInstances = $null + } Else { + IF ($RegionsManuallyEntered) { + Write-Host "Disabled or Invalid Region Specified: $region - Skipping" + } Else { + Write-Host "$Region not Enabled - Skipping" + } + } +} \ No newline at end of file diff --git a/DatabaseBackup.sql b/DatabaseBackup.sql index 4badbc06..c9828b77 100644 --- a/DatabaseBackup.sql +++ b/DatabaseBackup.sql @@ -20,7 +20,7 @@ ALTER PROCEDURE [dbo].[DatabaseBackup] @CopyOnly nvarchar(max) = 'N', @ChangeBackupType nvarchar(max) = 'N', @BackupSoftware nvarchar(max) = NULL, -@CheckSum nvarchar(max) = 'N', +@Checksum nvarchar(max) = 'N', @BlockSize int = NULL, @BufferCount int = NULL, @MaxTransferSize int = NULL, @@ -29,6 +29,7 @@ ALTER PROCEDURE [dbo].[DatabaseBackup] @MaxFileSize int = NULL, @CompressionLevel int = NULL, @Description nvarchar(max) = NULL, +@BackupSetName nvarchar(max) = NULL, @Threads int = NULL, @Throttle int = NULL, @Encrypt nvarchar(max) = 'N', @@ -49,6 +50,7 @@ ALTER PROCEDURE [dbo].[DatabaseBackup] @Updateability nvarchar(max) = 'ALL', @AdaptiveCompression nvarchar(max) = NULL, @ModificationLevel int = NULL, +@MinDatabaseSizeForDifferentialBackup int = NULL, @LogSizeSinceLastLogBackup int = NULL, @TimeSinceLastLogBackup int = NULL, @DataDomainBoostHost nvarchar(max) = NULL, @@ -71,9 +73,20 @@ ALTER PROCEDURE [dbo].[DatabaseBackup] @ExcludeLogShippedFromLogBackup nvarchar(max) = 'Y', @DirectoryCheck nvarchar(max) = 'Y', @BackupOptions nvarchar(max) = NULL, +@Stats int = NULL, +@ExpireDate datetime = NULL, +@RetainDays int = NULL, @StringDelimiter nvarchar(max) = ',', @DatabaseOrder nvarchar(max) = NULL, @DatabasesInParallel nvarchar(max) = 'N', + + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- +@S3BucketArn nvarchar(255) = NULL, +@kms_master_key_arn nvarchar(max) = NULL, + ---------------------------------------------------------------------------------------------------- + @LogToTable nvarchar(max) = 'N', @Execute nvarchar(max) = 'Y' @@ -85,7 +98,9 @@ BEGIN --// Source: https://ola.hallengren.com //-- --// License: https://ola.hallengren.com/license.html //-- --// GitHub: https://github.com/olahallengren/sql-server-maintenance-solution //-- - --// Version: 2024-12-27 18:10:28 //-- + --// Version: 2025-02-19 21:12:35 //-- + --// //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON @@ -138,6 +153,7 @@ BEGIN DECLARE @CurrentDifferentialBaseLSN numeric(25,0) DECLARE @CurrentDifferentialBaseIsSnapshot bit DECLARE @CurrentLogLSN numeric(25,0) + DECLARE @BackupInProcess bit DECLARE @CurrentLatestBackup datetime2 DECLARE @CurrentDatabaseNameFS nvarchar(max) DECLARE @CurrentDirectoryStructure nvarchar(max) @@ -145,11 +161,12 @@ BEGIN DECLARE @CurrentMaxFilePathLength nvarchar(max) DECLARE @CurrentFileName nvarchar(max) DECLARE @CurrentDirectoryID int - DECLARE @CurrentDirectoryPath nvarchar(max) + DECLARE @CurrentDirectoryPath nvarchar(4000) DECLARE @CurrentFilePath nvarchar(max) DECLARE @CurrentDate datetime2 DECLARE @CurrentDateUTC datetime2 DECLARE @CurrentCleanupDate datetime2 + DECLARE @CurrentReplicaID uniqueidentifier DECLARE @CurrentAvailabilityGroupID uniqueidentifier DECLARE @CurrentAvailabilityGroup nvarchar(max) @@ -261,6 +278,15 @@ BEGIN DECLARE @Version numeric(18,10) = CAST(LEFT(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)),CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max))) - 1) + '.' + REPLACE(RIGHT(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)), LEN(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max))) - CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)))),'.','') AS numeric(18,10)) + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + DECLARE @CurrentRDSBackupType nvarchar(20) + DECLARE @CurrentRDSDatabaseFileName nvarchar(4000) + + DECLARE @ServerName nvarchar(max) = CASE WHEN SERVERPROPERTY('EngineEdition') = 8 THEN LEFT(CAST(SERVERPROPERTY('ServerName') AS nvarchar(max)),CHARINDEX('.',CAST(SERVERPROPERTY('ServerName') AS nvarchar(max))) - 1) ELSE CAST(SERVERPROPERTY('MachineName') AS nvarchar(max)) END + ---------------------------------------------------------------------------------------------------- + IF @Version >= 14 BEGIN SELECT @HostPlatform = host_platform @@ -271,7 +297,7 @@ BEGIN SET @HostPlatform = 'Windows' END - DECLARE @AmazonRDS bit = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END + DECLARE @AmazonRDS bit = CASE WHEN EXISTS (SELECT * FROM sys.databases WHERE [name] = 'rdsadmin') AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END ---------------------------------------------------------------------------------------------------- --// Log initial information //-- @@ -288,7 +314,7 @@ BEGIN SET @Parameters += ', @CopyOnly = ' + ISNULL('''' + REPLACE(@CopyOnly,'''','''''') + '''','NULL') SET @Parameters += ', @ChangeBackupType = ' + ISNULL('''' + REPLACE(@ChangeBackupType,'''','''''') + '''','NULL') SET @Parameters += ', @BackupSoftware = ' + ISNULL('''' + REPLACE(@BackupSoftware,'''','''''') + '''','NULL') - SET @Parameters += ', @CheckSum = ' + ISNULL('''' + REPLACE(@CheckSum,'''','''''') + '''','NULL') + SET @Parameters += ', @Checksum = ' + ISNULL('''' + REPLACE(@Checksum,'''','''''') + '''','NULL') SET @Parameters += ', @BlockSize = ' + ISNULL(CAST(@BlockSize AS nvarchar),'NULL') SET @Parameters += ', @BufferCount = ' + ISNULL(CAST(@BufferCount AS nvarchar),'NULL') SET @Parameters += ', @MaxTransferSize = ' + ISNULL(CAST(@MaxTransferSize AS nvarchar),'NULL') @@ -297,6 +323,7 @@ BEGIN SET @Parameters += ', @MaxFileSize = ' + ISNULL(CAST(@MaxFileSize AS nvarchar),'NULL') SET @Parameters += ', @CompressionLevel = ' + ISNULL(CAST(@CompressionLevel AS nvarchar),'NULL') SET @Parameters += ', @Description = ' + ISNULL('''' + REPLACE(@Description,'''','''''') + '''','NULL') + SET @Parameters += ', @BackupSetName = ' + ISNULL('''' + REPLACE(@BackupSetName,'''','''''') + '''','NULL') SET @Parameters += ', @Threads = ' + ISNULL(CAST(@Threads AS nvarchar),'NULL') SET @Parameters += ', @Throttle = ' + ISNULL(CAST(@Throttle AS nvarchar),'NULL') SET @Parameters += ', @Encrypt = ' + ISNULL('''' + REPLACE(@Encrypt,'''','''''') + '''','NULL') @@ -317,6 +344,7 @@ BEGIN SET @Parameters += ', @Updateability = ' + ISNULL('''' + REPLACE(@Updateability,'''','''''') + '''','NULL') SET @Parameters += ', @AdaptiveCompression = ' + ISNULL('''' + REPLACE(@AdaptiveCompression,'''','''''') + '''','NULL') SET @Parameters += ', @ModificationLevel = ' + ISNULL(CAST(@ModificationLevel AS nvarchar),'NULL') + SET @Parameters += ', @MinDatabaseSizeForDifferentialBackup = ' + ISNULL('''' + REPLACE(@MinDatabaseSizeForDifferentialBackup,'''','''''') + '''','NULL') SET @Parameters += ', @LogSizeSinceLastLogBackup = ' + ISNULL(CAST(@LogSizeSinceLastLogBackup AS nvarchar),'NULL') SET @Parameters += ', @TimeSinceLastLogBackup = ' + ISNULL(CAST(@TimeSinceLastLogBackup AS nvarchar),'NULL') SET @Parameters += ', @DataDomainBoostHost = ' + ISNULL('''' + REPLACE(@DataDomainBoostHost,'''','''''') + '''','NULL') @@ -338,12 +366,23 @@ BEGIN SET @Parameters += ', @ObjectLevelRecoveryMap = ' + ISNULL('''' + REPLACE(@ObjectLevelRecoveryMap,'''','''''') + '''','NULL') SET @Parameters += ', @ExcludeLogShippedFromLogBackup = ' + ISNULL('''' + REPLACE(@ExcludeLogShippedFromLogBackup,'''','''''') + '''','NULL') SET @Parameters += ', @DirectoryCheck = ' + ISNULL('''' + REPLACE(@DirectoryCheck,'''','''''') + '''','NULL') + SET @Parameters += ', @BackupOptions = ' + ISNULL('''' + REPLACE(@BackupOptions,'''','''''') + '''','NULL') + SET @Parameters += ', @Stats = ' + ISNULL(CAST(@Stats AS nvarchar),'NULL') + SET @Parameters += ', @ExpireDate = ' + ISNULL('''' + CONVERT(nvarchar, @ExpireDate, 21) + '''','NULL') + SET @Parameters += ', @RetainDays = ' + ISNULL(CAST(@RetainDays AS nvarchar),'NULL') SET @Parameters += ', @StringDelimiter = ' + ISNULL('''' + REPLACE(@StringDelimiter,'''','''''') + '''','NULL') SET @Parameters += ', @DatabaseOrder = ' + ISNULL('''' + REPLACE(@DatabaseOrder,'''','''''') + '''','NULL') SET @Parameters += ', @DatabasesInParallel = ' + ISNULL('''' + REPLACE(@DatabasesInParallel,'''','''''') + '''','NULL') SET @Parameters += ', @LogToTable = ' + ISNULL('''' + REPLACE(@LogToTable,'''','''''') + '''','NULL') SET @Parameters += ', @Execute = ' + ISNULL('''' + REPLACE(@Execute,'''','''''') + '''','NULL') + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + SET @Parameters += ', @S3BucketArn = ' + ISNULL('''' + REPLACE(@S3BucketArn,'''','''''') + '''','NULL') + SET @Parameters += ', @kms_master_key_arn = ' + ISNULL('''' + REPLACE(@kms_master_key_arn,'''','''''') + '''','NULL') + ---------------------------------------------------------------------------------------------------- + SET @StartMessage = 'Date and time: ' + CONVERT(nvarchar,@StartTime,120) RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT @@ -359,7 +398,7 @@ BEGIN SET @StartMessage = 'Platform: ' + @HostPlatform RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT - SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME(DB_ID())) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) + SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME()) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT SET @StartMessage = 'Parameters: ' + @Parameters @@ -377,10 +416,10 @@ BEGIN --// Check core requirements //-- ---------------------------------------------------------------------------------------------------- - IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE database_id = DB_ID()) >= 90 + IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE [name] = DB_NAME()) >= 90 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The database ' + QUOTENAME(DB_NAME(DB_ID())) + ' has to be in compatibility level 90 or higher.', 16, 1 + SELECT 'The database ' + QUOTENAME(DB_NAME()) + ' has to be in compatibility level 90 or higher.', 16, 1 END IF NOT (SELECT uses_ansi_nulls FROM sys.sql_modules WHERE [object_id] = @@PROCID) = 1 @@ -431,11 +470,36 @@ BEGIN SELECT 'The transaction count is not 0.', 16, 1 END - IF @AmazonRDS = 1 + --IF @AmazonRDS = 1 AND (@S3BucketArn = NULL OR @S3BucketArn = '') + --BEGIN + -- INSERT INTO @Errors ([Message], Severity, [State]) + -- SELECT 'The parameter @S3BucketArn is a required for Amazon RDS backups.', 16, 1 + --END + + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF (@AmazonRDS = 1) BEGIN - INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The stored procedure DatabaseBackup is not supported on Amazon RDS.', 16, 1 + IF (@AmazonRDS = 1 AND @S3BucketArn IS NULL) OR (@AmazonRDS = 1 AND @S3BucketArn = '') + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The parameter @S3BucketArn is a required for Amazon RDS backups.', 16, 1 + END + + IF (@S3BucketArn NOT LIKE 'arn:aws:s3:%' AND @S3BucketArn != '') + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The parameter @S3BucketArn is invalid.', 16, 1 + END + + IF (@kms_master_key_arn NOT LIKE 'arn:aws:kms:%' AND @kms_master_key_arn != '') + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The parameter @kms_master_key_arn is invalid.', 16, 1 + END END + ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- --// Select databases //-- @@ -691,8 +755,8 @@ BEGIN SET @ErrorMessage = '' SELECT @ErrorMessage = @ErrorMessage + QUOTENAME(DatabaseName) + ', ' FROM @tmpDatabases - WHERE UPPER(DatabaseNameFS) IN(SELECT UPPER(DatabaseNameFS) FROM @tmpDatabases GROUP BY UPPER(DatabaseNameFS) HAVING COUNT(*) > 1) - AND UPPER(DatabaseNameFS) IN(SELECT UPPER(DatabaseNameFS) FROM @tmpDatabases WHERE Selected = 1) + WHERE UPPER(DatabaseNameFS) IN(SELECT UPPER(DatabaseNameFS) FROM @tmpDatabases GROUP BY UPPER(DatabaseNameFS) HAVING COUNT(*) > 1 AND MAX(CAST(Selected AS int)) = 1) + AND DATALENGTH(DatabaseNameFS) > 0 ORDER BY DatabaseName ASC OPTION (RECOMPILE) @@ -886,14 +950,21 @@ BEGIN BREAK END - INSERT INTO @DirectoryInfo (FileExists, FileIsADirectory, ParentDirectoryExists) - EXECUTE [master].dbo.xp_fileexist @CurrentRootDirectoryPath - - IF NOT EXISTS (SELECT * FROM @DirectoryInfo WHERE FileExists = 0 AND FileIsADirectory = 1 AND ParentDirectoryExists = 1) - BEGIN - INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The directory ' + @CurrentRootDirectoryPath + ' does not exist.', 16, 1 + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @AmazonRDS = 0 + BEGIN + INSERT INTO @DirectoryInfo (FileExists, FileIsADirectory, ParentDirectoryExists) + EXECUTE [master].dbo.xp_fileexist @CurrentRootDirectoryPath + + IF NOT EXISTS (SELECT * FROM @DirectoryInfo WHERE FileExists = 0 AND FileIsADirectory = 1 AND ParentDirectoryExists = 1) + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The directory ' + @CurrentRootDirectoryPath + ' does not exist.', 16, 1 + END END + ---------------------------------------------------------------------------------------------------- UPDATE @Directories SET Completed = 1 @@ -1137,7 +1208,11 @@ BEGIN IF @CleanupTime IS NOT NULL AND @URL IS NOT NULL BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The value for the parameter @CleanupTime is not supported. Cleanup is not supported on Azure Blob Storage.', 16, 2 + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + SELECT 'The value for the parameter @CleanupTime is not supported. Cleanup is not supported on Amazon S3 or Azure Blob Storage.', 16, 2 + ---------------------------------------------------------------------------------------------------- END IF @CleanupTime IS NOT NULL AND EXISTS(SELECT * FROM @Directories WHERE DirectoryPath = 'NUL') @@ -1152,10 +1227,10 @@ BEGIN SELECT 'The value for the parameter @CleanupTime is not supported. Cleanup is not supported if the token {DatabaseName} is not part of the directory.', 16, 5 END - IF @CleanupTime IS NOT NULL AND ((@DirectoryStructure NOT LIKE '%{BackupType}%' OR @DirectoryStructure IS NULL) OR (SERVERPROPERTY('IsHadrEnabled') = 1 AND (@AvailabilityGroupDirectoryStructure NOT LIKE '%{BackupType}%' OR @AvailabilityGroupDirectoryStructure IS NULL))) + IF @CleanupTime IS NOT NULL AND ((@DirectoryStructure NOT LIKE '%{BackupType}%' OR @DirectoryStructure IS NULL) OR (SERVERPROPERTY('IsHadrEnabled') = 1 AND (@AvailabilityGroupDirectoryStructure NOT LIKE '%{BackupType}%' OR @AvailabilityGroupDirectoryStructure IS NULL))) AND (SELECT COUNT(*) FROM (SELECT @FileExtensionFull AS FileExtension UNION SELECT @FileExtensionDiff UNION SELECT @FileExtensionLog) FileExtension) <> 3 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The value for the parameter @CleanupTime is not supported. Cleanup is not supported if the token {BackupType} is not part of the directory.', 16, 6 + SELECT 'The value for the parameter @CleanupTime is not supported. Cleanup is not supported if the token {BackupType} is not part of the directory and the file extensions are not unique.', 16, 6 END IF @CleanupTime IS NOT NULL AND @CopyOnly = 'Y' AND ((@DirectoryStructure NOT LIKE '%{CopyOnly}%' OR @DirectoryStructure IS NULL) OR (SERVERPROPERTY('IsHadrEnabled') = 1 AND (@AvailabilityGroupDirectoryStructure NOT LIKE '%{CopyOnly}%' OR @AvailabilityGroupDirectoryStructure IS NULL))) @@ -1280,10 +1355,10 @@ BEGIN ---------------------------------------------------------------------------------------------------- - IF @CheckSum NOT IN ('Y','N') OR @CheckSum IS NULL + IF @Checksum NOT IN ('Y','N') OR @Checksum IS NULL BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The value for the parameter @CheckSum is not supported.', 16, 1 + SELECT 'The value for the parameter @Checksum is not supported.', 16, 1 END ---------------------------------------------------------------------------------------------------- @@ -1432,6 +1507,16 @@ BEGIN SELECT 'The value for the parameter @NumberOfFiles is not supported. The maximum number of files when performing mirrored backups to S3 storage is 32.', 16, 10 END + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @NumberOfFiles > 10 AND @AmazonRDS = 1 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @NumberOfFiles is not supported. The maximum number of files when performing Amazon RDS backups is 10.', 16, 10 + END + ---------------------------------------------------------------------------------------------------- + ---------------------------------------------------------------------------------------------------- IF @MinBackupSizeForMultipleFiles <= 0 @@ -1538,6 +1623,13 @@ BEGIN ---------------------------------------------------------------------------------------------------- + IF LEN(@BackupSetName) > 128 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @BackupSetName is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- IF @Threads IS NOT NULL AND (@BackupSoftware NOT IN('LITESPEED','SQLBACKUP','SQLSAFE') OR @BackupSoftware IS NULL) BEGIN INSERT INTO @Errors ([Message], Severity, [State]) @@ -1885,16 +1977,35 @@ BEGIN SELECT 'The value for the parameter @ModificationLevel is not supported.', 16, 1 END + IF @ModificationLevel <= 0 OR @ModificationLevel > 100 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @ModificationLevel is not supported.', 16, 2 + END IF @ModificationLevel IS NOT NULL AND @ChangeBackupType = 'N' BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The parameter @ModificationLevel can only be used together with @ChangeBackupType = ''Y''.', 16, 2 + SELECT 'The parameter @ModificationLevel can only be used together with @ChangeBackupType = ''Y''.', 16, 3 END IF @ModificationLevel IS NOT NULL AND @BackupType <> 'DIFF' BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The parameter @ModificationLevel can only be used for differential backups.', 16, 3 + SELECT 'The parameter @ModificationLevel can only be used for differential backups.', 16, 4 + END + + ---------------------------------------------------------------------------------------------------- + + IF @MinDatabaseSizeForDifferentialBackup <= 0 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @MinDatabaseSizeForDifferentialBackup is not supported.', 16, 1 + END + + IF @MinDatabaseSizeForDifferentialBackup IS NOT NULL AND @BackupType <> 'DIFF' + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The parameter @MinDatabaseSizeForDifferentialBackup can only be used for differential backups.', 16, 2 END ---------------------------------------------------------------------------------------------------- @@ -2099,7 +2210,7 @@ BEGIN ---------------------------------------------------------------------------------------------------- - IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@DirectoryStructure,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{MajorVersion}',''),'{MinorVersion}','') AS DirectoryStructure) Temp WHERE DirectoryStructure LIKE '%{%' OR DirectoryStructure LIKE '%}%') + IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@DirectoryStructure,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{BackupSetName}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Weekday}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{MajorVersion}',''),'{MinorVersion}','') AS DirectoryStructure) Temp WHERE DirectoryStructure LIKE '%{%' OR DirectoryStructure LIKE '%}%') BEGIN INSERT INTO @Errors ([Message], Severity, [State]) SELECT 'The parameter @DirectoryStructure contains one or more tokens that are not supported.', 16, 1 @@ -2107,7 +2218,7 @@ BEGIN ---------------------------------------------------------------------------------------------------- - IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@AvailabilityGroupDirectoryStructure,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{MajorVersion}',''),'{MinorVersion}','') AS AvailabilityGroupDirectoryStructure) Temp WHERE AvailabilityGroupDirectoryStructure LIKE '%{%' OR AvailabilityGroupDirectoryStructure LIKE '%}%') + IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@AvailabilityGroupDirectoryStructure,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{BackupSetName}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Weekday}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{MajorVersion}',''),'{MinorVersion}','') AS AvailabilityGroupDirectoryStructure) Temp WHERE AvailabilityGroupDirectoryStructure LIKE '%{%' OR AvailabilityGroupDirectoryStructure LIKE '%}%') BEGIN INSERT INTO @Errors ([Message], Severity, [State]) SELECT 'The parameter @AvailabilityGroupDirectoryStructure contains one or more tokens that are not supported.', 16, 1 @@ -2115,7 +2226,7 @@ BEGIN ---------------------------------------------------------------------------------------------------- - IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@FileName,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{FileNumber}',''),'{NumberOfFiles}',''),'{FileExtension}',''),'{MajorVersion}',''),'{MinorVersion}','') AS [FileName]) Temp WHERE [FileName] LIKE '%{%' OR [FileName] LIKE '%}%') + IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@FileName,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{BackupSetName}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Weekday}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{FileNumber}',''),'{NumberOfFiles}',''),'{FileExtension}',''),'{MajorVersion}',''),'{MinorVersion}','') AS [FileName]) Temp WHERE [FileName] LIKE '%{%' OR [FileName] LIKE '%}%') BEGIN INSERT INTO @Errors ([Message], Severity, [State]) SELECT 'The parameter @FileName contains one or more tokens that are not supported.', 16, 1 @@ -2123,7 +2234,7 @@ BEGIN ---------------------------------------------------------------------------------------------------- - IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@AvailabilityGroupFileName,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{FileNumber}',''),'{NumberOfFiles}',''),'{FileExtension}',''),'{MajorVersion}',''),'{MinorVersion}','') AS AvailabilityGroupFileName) Temp WHERE AvailabilityGroupFileName LIKE '%{%' OR AvailabilityGroupFileName LIKE '%}%') + IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@AvailabilityGroupFileName,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{BackupSetName}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Weekday}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{FileNumber}',''),'{NumberOfFiles}',''),'{FileExtension}',''),'{MajorVersion}',''),'{MinorVersion}','') AS AvailabilityGroupFileName) Temp WHERE AvailabilityGroupFileName LIKE '%{%' OR AvailabilityGroupFileName LIKE '%}%') BEGIN INSERT INTO @Errors ([Message], Severity, [State]) SELECT 'The parameter @AvailabilityGroupFileName contains one or more tokens that are not supported.', 16, 1 @@ -2245,6 +2356,43 @@ BEGIN ---------------------------------------------------------------------------------------------------- + IF @BackupOptions IS NOT NULL AND @URL IS NULL + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @BackupOptions is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- + + IF @Stats <= 0 OR @Stats > 100 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @Stats is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- + + IF @ExpireDate IS NOT NULL AND @BackupSoftware <> 'LITESPEED' + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @ExpireDate is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- + + IF @RetainDays < 0 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @RetainDays is not supported.', 16, 1 + END + + IF @RetainDays IS NOT NULL AND @BackupSoftware <> 'LITESPEED' + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @RetainDays is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- IF @StringDelimiter IS NULL OR LEN(@StringDelimiter) > 1 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) @@ -2721,22 +2869,23 @@ BEGIN AND EXISTS(SELECT * FROM sys.all_columns WHERE object_id = OBJECT_ID('sys.dm_db_file_space_usage') AND name = 'modified_extent_page_count') AND (@CurrentAvailabilityGroupRole = 'PRIMARY' OR @CurrentAvailabilityGroupRole IS NULL) AND (@BackupType IN('DIFF','FULL') OR (@ChangeBackupType = 'Y' AND @CurrentBackupType = 'LOG' AND @CurrentRecoveryModel IN('FULL','BULK_LOGGED') AND @CurrentLogLSN IS NULL AND @CurrentDatabaseName <> 'master')) - AND (@ModificationLevel IS NOT NULL OR @MinBackupSizeForMultipleFiles IS NOT NULL OR @MaxFileSize IS NOT NULL) + AND (@ModificationLevel IS NOT NULL OR @MinBackupSizeForMultipleFiles IS NOT NULL OR @MaxFileSize IS NOT NULL OR @MinDatabaseSizeForDifferentialBackup IS NOT NULL) BEGIN SET @CurrentCommand = 'SELECT @ParamAllocatedExtentPageCount = SUM(allocated_extent_page_count), @ParamModifiedExtentPageCount = SUM(modified_extent_page_count) FROM sys.dm_db_file_space_usage' EXECUTE @CurrentDatabase_sp_executesql @stmt = @CurrentCommand, @params = N'@ParamAllocatedExtentPageCount bigint OUTPUT, @ParamModifiedExtentPageCount bigint OUTPUT', @ParamAllocatedExtentPageCount = @CurrentAllocatedExtentPageCount OUTPUT, @ParamModifiedExtentPageCount = @CurrentModifiedExtentPageCount OUTPUT END + SET @BackupInProcess = CASE WHEN EXISTS(SELECT * FROM sys.dm_exec_requests WHERE database_id = DB_ID(@CurrentDatabaseName) AND command = 'BACKUP DATABASE') THEN 1 ELSE 0 END SET @CurrentBackupType = @BackupType IF @ChangeBackupType = 'Y' BEGIN - IF @CurrentBackupType = 'LOG' AND @CurrentRecoveryModel IN('FULL','BULK_LOGGED') AND @CurrentLogLSN IS NULL AND @CurrentDatabaseName <> 'master' + IF @CurrentBackupType = 'LOG' AND @CurrentRecoveryModel IN('FULL','BULK_LOGGED') AND @CurrentLogLSN IS NULL AND @CurrentDatabaseName <> 'master' AND @BackupInProcess = 0 BEGIN SET @CurrentBackupType = 'DIFF' END - IF @CurrentBackupType = 'DIFF' AND (@CurrentDatabaseName = 'master' OR @CurrentDifferentialBaseLSN IS NULL OR (@CurrentModifiedExtentPageCount * 1. / @CurrentAllocatedExtentPageCount * 100 >= @ModificationLevel)) + IF @CurrentBackupType = 'DIFF' AND (@CurrentDatabaseName = 'master' OR @CurrentDifferentialBaseLSN IS NULL OR (@CurrentModifiedExtentPageCount * 1. / @CurrentAllocatedExtentPageCount * 100 >= @ModificationLevel) OR (COALESCE(CAST(@CurrentAllocatedExtentPageCount AS bigint) * 8192, CAST(@CurrentDatabaseSize AS bigint) * 8192) < CAST(@MinDatabaseSizeForDifferentialBackup AS bigint) * 1024 * 1024)) BEGIN SET @CurrentBackupType = 'FULL' END @@ -2793,18 +2942,32 @@ BEGIN FROM CurrentDatabase SELECT @CurrentDatabaseMirroringRole = UPPER(mirroring_role_desc) - FROM sys.database_mirroring - WHERE database_id = DB_ID(@CurrentDatabaseName) + FROM sys.database_mirroring database_mirroring + INNER JOIN sys.databases databases ON database_mirroring.database_id = databases.database_id + WHERE databases.[name] = @CurrentDatabaseName - IF EXISTS (SELECT * FROM msdb.dbo.log_shipping_primary_databases WHERE primary_database = @CurrentDatabaseName) - BEGIN - SET @CurrentLogShippingRole = 'PRIMARY' - END - ELSE - IF EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondary_databases WHERE secondary_database = @CurrentDatabaseName) + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @AmazonRDS = 0 BEGIN - SET @CurrentLogShippingRole = 'SECONDARY' - END + IF EXISTS (SELECT * FROM msdb.dbo.log_shipping_primary_databases WHERE primary_database = @CurrentDatabaseName) + BEGIN + SET @CurrentLogShippingRole = 'PRIMARY' + END + ELSE + IF EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondary_databases WHERE secondary_database = @CurrentDatabaseName) + BEGIN + SET @CurrentLogShippingRole = 'SECONDARY' + END + END + ---------------------------------------------------------------------------------------------------- + + + + + + IF @CurrentAvailabilityGroup IS NOT NULL BEGIN @@ -2845,6 +3008,11 @@ BEGIN SET @DatabaseMessage = 'Last log backup LSN: ' + ISNULL(CAST(@CurrentLogLSN AS nvarchar),'N/A') RAISERROR('%s',10,1,@DatabaseMessage) WITH NOWAIT + IF @CurrentBackupType = 'LOG' AND @BackupInProcess = 1 + BEGIN + SET @DatabaseMessage = 'Full or differential backup in process: ' + CASE WHEN @BackupInProcess = 1 THEN 'Yes' WHEN @BackupInProcess = 0 THEN 'No' ELSE 'N/A' END + RAISERROR('%s',10,1,@DatabaseMessage) WITH NOWAIT + END IF @CurrentBackupType IN('DIFF','FULL') AND EXISTS(SELECT * FROM sys.all_columns WHERE object_id = OBJECT_ID('sys.dm_db_file_space_usage') AND name = 'modified_extent_page_count') BEGIN SET @DatabaseMessage = 'Allocated extent page count: ' + ISNULL(CAST(@CurrentAllocatedExtentPageCount AS nvarchar) + ' (' + CAST(@CurrentAllocatedExtentPageCount * 1. * 8 / 1024 AS nvarchar) + ' MB)','N/A') @@ -2882,6 +3050,7 @@ BEGIN AND NOT (@CurrentIsReadOnly = 0 AND @Updateability = 'READ_ONLY') AND NOT (@CurrentBackupType = 'LOG' AND @LogSizeSinceLastLogBackup IS NOT NULL AND @TimeSinceLastLogBackup IS NOT NULL AND NOT(@CurrentLogSizeSinceLastLogBackup >= @LogSizeSinceLastLogBackup OR @CurrentLogSizeSinceLastLogBackup IS NULL OR DATEDIFF(SECOND,@CurrentLastLogBackup,SYSDATETIME()) >= @TimeSinceLastLogBackup OR @CurrentLastLogBackup IS NULL)) AND NOT (@CurrentBackupType = 'LOG' AND @Updateability = 'READ_ONLY' AND @BackupSoftware = 'DATA_DOMAIN_BOOST') + AND NOT (@CurrentBackupType = 'DIFF' AND @MinDatabaseSizeForDifferentialBackup IS NOT NULL AND (COALESCE(CAST(@CurrentAllocatedExtentPageCount AS bigint) * 8192, CAST(@CurrentDatabaseSize AS bigint) * 8192) < CAST(@MinDatabaseSizeForDifferentialBackup AS bigint) * 1024 * 1024)) BEGIN IF @CurrentBackupType = 'LOG' AND (@CleanupTime IS NOT NULL OR @MirrorCleanupTime IS NOT NULL) @@ -2921,6 +3090,7 @@ BEGIN IF SERVERPROPERTY('InstanceName') IS NULL SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{InstanceName}','') IF @@SERVICENAME IS NULL SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{ServiceName}','') IF @Description IS NULL SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Description}','') + IF @BackupSetName IS NULL SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{BackupSetName}','') IF @Directory IS NULL AND @MirrorDirectory IS NULL AND @URL IS NULL AND @DefaultDirectory LIKE '%' + '.' + @@SERVICENAME + @DirectorySeparator + 'MSSQL' + @DirectorySeparator + 'Backup' BEGIN @@ -3078,10 +3248,12 @@ BEGIN SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Partial}','PARTIAL') SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{CopyOnly}','COPY_ONLY') SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Description}',LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ISNULL(@Description,''),'\',''),'/',''),':',''),'*',''),'?',''),'"',''),'<',''),'>',''),'|','')))) + SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{BackupSetName}',LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ISNULL(@BackupSetName,''),'\',''),'/',''),':',''),'*',''),'?',''),'"',''),'<',''),'>',''),'|','')))) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Year}',CAST(DATEPART(YEAR,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Month}',RIGHT('0' + CAST(DATEPART(MONTH,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Day}',RIGHT('0' + CAST(DATEPART(DAY,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Week}',RIGHT('0' + CAST(DATEPART(WEEK,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) + SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Weekday}',DATENAME(WEEKDAY,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Hour}',RIGHT('0' + CAST(DATEPART(HOUR,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Minute}',RIGHT('0' + CAST(DATEPART(MINUTE,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Second}',RIGHT('0' + CAST(DATEPART(SECOND,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) @@ -3128,6 +3300,7 @@ BEGIN IF SERVERPROPERTY('InstanceName') IS NULL SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{InstanceName}','') IF @@SERVICENAME IS NULL SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{ServiceName}','') IF @Description IS NULL SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Description}','') + IF @BackupSetName IS NULL SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{BackupSetName}','') IF @CurrentNumberOfFiles = 1 SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{FileNumber}','') IF @CurrentNumberOfFiles = 1 SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{NumberOfFiles}','') @@ -3239,10 +3412,12 @@ BEGIN SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Partial}','PARTIAL') SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{CopyOnly}','COPY_ONLY') SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Description}',LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ISNULL(@Description,''),'\',''),'/',''),':',''),'*',''),'?',''),'"',''),'<',''),'>',''),'|','')))) + SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{BackupSetName}',LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ISNULL(@BackupSetName,''),'\',''),'/',''),':',''),'*',''),'?',''),'"',''),'<',''),'>',''),'|','')))) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Year}',CAST(DATEPART(YEAR,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Month}',RIGHT('0' + CAST(DATEPART(MONTH,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Day}',RIGHT('0' + CAST(DATEPART(DAY,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Week}',RIGHT('0' + CAST(DATEPART(WEEK,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) + SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Weekday}',DATENAME(WEEKDAY,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Hour}',RIGHT('0' + CAST(DATEPART(HOUR,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Minute}',RIGHT('0' + CAST(DATEPART(MINUTE,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Second}',RIGHT('0' + CAST(DATEPART(SECOND,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) @@ -3405,6 +3580,13 @@ BEGIN -- Create directory IF @HostPlatform = 'Windows' AND (@BackupSoftware <> 'DATA_DOMAIN_BOOST' OR @BackupSoftware IS NULL) + + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + AND (@AmazonRDS = 0) + ---------------------------------------------------------------------------------------------------- + AND NOT EXISTS(SELECT * FROM @CurrentDirectories WHERE DirectoryPath = 'NUL' OR DirectoryPath IN(SELECT DirectoryPath FROM @Directories)) BEGIN WHILE (1 = 1) @@ -3420,21 +3602,40 @@ BEGIN BREAK END - SET @CurrentDatabaseContext = 'master' + IF @DirectoryCheck = 'Y' + BEGIN + INSERT INTO @DirectoryInfo (FileExists, FileIsADirectory, ParentDirectoryExists) + EXECUTE [master].dbo.xp_fileexist @CurrentDirectoryPath + END - SET @CurrentCommandType = 'xp_create_subdir' + IF NOT EXISTS (SELECT * FROM @DirectoryInfo WHERE FileExists = 0 AND FileIsADirectory = 1 AND ParentDirectoryExists = 1) + BEGIN + SET @CurrentDatabaseContext = 'master' - SET @CurrentCommand = 'DECLARE @ReturnCode int EXECUTE @ReturnCode = dbo.xp_create_subdir N''' + REPLACE(@CurrentDirectoryPath,'''','''''') + ''' IF @ReturnCode <> 0 RAISERROR(''Error creating directory.'', 16, 1)' + SET @CurrentCommandType = 'xp_create_subdir' - EXECUTE @CurrentCommandOutput = dbo.CommandExecute @DatabaseContext = @CurrentDatabaseContext, @Command = @CurrentCommand, @CommandType = @CurrentCommandType, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute - SET @Error = @@ERROR - IF @Error <> 0 SET @CurrentCommandOutput = @Error - IF @CurrentCommandOutput <> 0 SET @ReturnCode = @CurrentCommandOutput + SET @CurrentCommand = 'DECLARE @ReturnCode int EXECUTE @ReturnCode = dbo.xp_create_subdir N''' + REPLACE(@CurrentDirectoryPath,'''','''''') + ''' IF @ReturnCode <> 0 RAISERROR(''Error creating directory.'', 16, 1)' + + + - UPDATE @CurrentDirectories - SET CreateCompleted = 1, - CreateOutput = @CurrentCommandOutput - WHERE ID = @CurrentDirectoryID + EXECUTE @CurrentCommandOutput = dbo.CommandExecute @DatabaseContext = @CurrentDatabaseContext, @Command = @CurrentCommand, @CommandType = @CurrentCommandType, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute + SET @Error = @@ERROR + IF @Error <> 0 SET @CurrentCommandOutput = @Error + IF @CurrentCommandOutput <> 0 SET @ReturnCode = @CurrentCommandOutput + + UPDATE @CurrentDirectories + SET CreateCompleted = 1, + CreateOutput = @CurrentCommandOutput + WHERE ID = @CurrentDirectoryID + END + ELSE + BEGIN + UPDATE @CurrentDirectories + SET CreateCompleted = 1, + CreateOutput = 0 + WHERE ID = @CurrentDirectoryID + END SET @CurrentDirectoryID = NULL SET @CurrentDirectoryPath = NULL @@ -3443,6 +3644,8 @@ BEGIN SET @CurrentCommand = NULL SET @CurrentCommandOutput = NULL SET @CurrentCommandType = NULL + + DELETE FROM @DirectoryInfo END END @@ -3558,77 +3761,117 @@ BEGIN -- Perform a backup IF NOT EXISTS (SELECT * FROM @CurrentDirectories WHERE DirectoryPath <> 'NUL' AND DirectoryPath NOT IN(SELECT DirectoryPath FROM @Directories) AND (CreateOutput <> 0 OR CreateOutput IS NULL)) - OR @HostPlatform = 'Linux' + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + OR @HostPlatform = 'Linux' OR @AmazonRDS = 1 BEGIN IF @BackupSoftware IS NULL - BEGIN - SET @CurrentDatabaseContext = 'master' - SELECT @CurrentCommandType = CASE - WHEN @CurrentBackupType IN('DIFF','FULL') THEN 'BACKUP_DATABASE' - WHEN @CurrentBackupType = 'LOG' THEN 'BACKUP_LOG' - END - - SELECT @CurrentCommand = CASE - WHEN @CurrentBackupType IN('DIFF','FULL') THEN 'BACKUP DATABASE ' + QUOTENAME(@CurrentDatabaseName) - WHEN @CurrentBackupType = 'LOG' THEN 'BACKUP LOG ' + QUOTENAME(@CurrentDatabaseName) - END - - IF @ReadWriteFileGroups = 'Y' AND @CurrentDatabaseName <> 'master' SET @CurrentCommand += ' READ_WRITE_FILEGROUPS' - - SET @CurrentCommand += ' TO' - - SELECT @CurrentCommand += ' ' + [Type] + ' = N''' + REPLACE(FilePath,'''','''''') + '''' + CASE WHEN ROW_NUMBER() OVER (ORDER BY FilePath ASC) <> @CurrentNumberOfFiles THEN ',' ELSE '' END - FROM @CurrentFiles - WHERE Mirror = 0 - ORDER BY FilePath ASC - - IF EXISTS(SELECT * FROM @CurrentFiles WHERE Mirror = 1) - BEGIN - SET @CurrentCommand += ' MIRROR TO' - - SELECT @CurrentCommand += ' ' + [Type] + ' = N''' + REPLACE(FilePath,'''','''''') + '''' + CASE WHEN ROW_NUMBER() OVER (ORDER BY FilePath ASC) <> @CurrentNumberOfFiles THEN ',' ELSE '' END - FROM @CurrentFiles - WHERE Mirror = 1 - ORDER BY FilePath ASC - END - - SET @CurrentCommand += ' WITH ' - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' - - IF @Version >= 10 - BEGIN - SET @CurrentCommand += CASE WHEN @Compress = 'Y' AND (@CurrentIsEncrypted = 0 OR (@CurrentIsEncrypted = 1 AND ((@Version >= 13 AND @CurrentMaxTransferSize >= 65537) OR @Version >= 15.0404316 OR SERVERPROPERTY('EngineEdition') = 8))) THEN ', COMPRESSION' ELSE ', NO_COMPRESSION' END - END - - IF @Compress = 'Y' AND @CompressionAlgorithm IS NOT NULL - BEGIN - SET @CurrentCommand += ' (ALGORITHM = ' + @CompressionAlgorithm + ')' - END - - IF @CurrentBackupType = 'DIFF' SET @CurrentCommand += ', DIFFERENTIAL' - - IF EXISTS(SELECT * FROM @CurrentFiles WHERE Mirror = 1) - BEGIN - SET @CurrentCommand += ', FORMAT' - END - - IF @CopyOnly = 'Y' SET @CurrentCommand += ', COPY_ONLY' - IF @NoRecovery = 'Y' AND @CurrentBackupType = 'LOG' SET @CurrentCommand += ', NORECOVERY' - IF @Init = 'Y' SET @CurrentCommand += ', INIT' - IF @Format = 'Y' SET @CurrentCommand += ', FORMAT' - IF @BlockSize IS NOT NULL SET @CurrentCommand += ', BLOCKSIZE = ' + CAST(@BlockSize AS nvarchar) - IF @BufferCount IS NOT NULL SET @CurrentCommand += ', BUFFERCOUNT = ' + CAST(@BufferCount AS nvarchar) - IF @CurrentMaxTransferSize IS NOT NULL SET @CurrentCommand += ', MAXTRANSFERSIZE = ' + CAST(@CurrentMaxTransferSize AS nvarchar) - IF @Description IS NOT NULL SET @CurrentCommand += ', DESCRIPTION = N''' + REPLACE(@Description,'''','''''') + '''' - IF @BackupOptions IS NOT NULL SET @CurrentCommand += ', BACKUP_OPTIONS = N''' + REPLACE(@BackupOptions,'''','''''') + '''' - IF @Encrypt = 'Y' SET @CurrentCommand += ', ENCRYPTION (ALGORITHM = ' + UPPER(@EncryptionAlgorithm) + ', ' - IF @Encrypt = 'Y' AND @ServerCertificate IS NOT NULL SET @CurrentCommand += 'SERVER CERTIFICATE = ' + QUOTENAME(@ServerCertificate) - IF @Encrypt = 'Y' AND @ServerAsymmetricKey IS NOT NULL SET @CurrentCommand += 'SERVER ASYMMETRIC KEY = ' + QUOTENAME(@ServerAsymmetricKey) - IF @Encrypt = 'Y' SET @CurrentCommand += ')' - IF @URL IS NOT NULL AND @Credential IS NOT NULL SET @CurrentCommand += ', CREDENTIAL = N''' + REPLACE(@Credential,'''','''''') + '''' - END + BEGIN + IF @AmazonRDS = 1 + BEGIN + SET @CurrentDatabaseContext = 'master' + + SELECT @CurrentCommandType = CASE + WHEN @CurrentBackupType IN('DIFF','FULL') THEN 'BACKUP_DATABASE' + + END + + SELECT @CurrentRDSBackupType = CASE + WHEN @CurrentBackupType = 'DIFF' THEN 'DIFFERENTIAL' + WHEN @CurrentBackupType = 'FULL' THEN 'FULL' + END + + IF @CurrentNumberOfFiles > 10 SET @CurrentNumberOfFiles = 10 + + SET @CurrentDatabaseFileName = @ServerName + '/' + @CurrentDatabaseFileName + + IF @CurrentNumberOfFiles > 1 + SELECT @CurrentDatabaseFileName=REPLACE(@CurrentDatabaseFileName,'_{FileNumber}','*'); + + IF (@kms_master_key_arn IS NULL) + SET @kms_master_key_arn = '' + + SET @CurrentCommand = 'EXEC msdb.dbo.rds_backup_database @source_db_name = ' + QUOTENAME(@CurrentDatabaseName) + ', @s3_arn_to_backup_to = ' + '''' + @S3BucketArn + '/' + @CurrentDatabaseFileName + '''' + ', @kms_master_key_arn = ' + '''' + @kms_master_key_arn + '''' + ', @overwrite_s3_backup_file=1 ' + ', @type=' + '''' + @CurrentRDSBackupType + '''' + ', @number_of_files= ' + CAST(@CurrentNumberOfFiles AS VarChar(2)) + ';' + END + ELSE + ---------------------------------------------------------------------------------------------------- + BEGIN + SET @CurrentDatabaseContext = 'master' + + SELECT @CurrentCommandType = CASE + WHEN @CurrentBackupType IN('DIFF','FULL') THEN 'BACKUP_DATABASE' + WHEN @CurrentBackupType = 'LOG' THEN 'BACKUP_LOG' + END + + SELECT @CurrentCommand = CASE + WHEN @CurrentBackupType IN('DIFF','FULL') THEN 'BACKUP DATABASE ' + QUOTENAME(@CurrentDatabaseName) + WHEN @CurrentBackupType = 'LOG' THEN 'BACKUP LOG ' + QUOTENAME(@CurrentDatabaseName) + END + + + + IF @ReadWriteFileGroups = 'Y' AND @CurrentDatabaseName <> 'master' SET @CurrentCommand += ' READ_WRITE_FILEGROUPS' + + SET @CurrentCommand += ' TO' + + SELECT @CurrentCommand += ' ' + [Type] + ' = N''' + REPLACE(FilePath,'''','''''') + '''' + CASE WHEN ROW_NUMBER() OVER (ORDER BY FilePath ASC) <> @CurrentNumberOfFiles THEN ',' ELSE '' END + FROM @CurrentFiles + WHERE Mirror = 0 + ORDER BY FilePath ASC + + IF EXISTS(SELECT * FROM @CurrentFiles WHERE Mirror = 1) + BEGIN + SET @CurrentCommand += ' MIRROR TO' + + SELECT @CurrentCommand += ' ' + [Type] + ' = N''' + REPLACE(FilePath,'''','''''') + '''' + CASE WHEN ROW_NUMBER() OVER (ORDER BY FilePath ASC) <> @CurrentNumberOfFiles THEN ',' ELSE '' END + FROM @CurrentFiles + WHERE Mirror = 1 + ORDER BY FilePath ASC + END + + SET @CurrentCommand += ' WITH ' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + + IF @Version >= 10 + BEGIN + SET @CurrentCommand += CASE WHEN @Compress = 'Y' AND (@CurrentIsEncrypted = 0 OR (@CurrentIsEncrypted = 1 AND ((@Version >= 13 AND @CurrentMaxTransferSize >= 65537) OR @Version >= 15.0404316 OR SERVERPROPERTY('EngineEdition') = 8))) THEN ', COMPRESSION' ELSE ', NO_COMPRESSION' END + END + + IF @Compress = 'Y' AND @CompressionAlgorithm IS NOT NULL + BEGIN + SET @CurrentCommand += ' (ALGORITHM = ' + @CompressionAlgorithm + ')' + END + + IF @CurrentBackupType = 'DIFF' SET @CurrentCommand += ', DIFFERENTIAL' + + IF EXISTS(SELECT * FROM @CurrentFiles WHERE Mirror = 1) + BEGIN + SET @CurrentCommand += ', FORMAT' + END + + IF @CopyOnly = 'Y' SET @CurrentCommand += ', COPY_ONLY' + IF @NoRecovery = 'Y' AND @CurrentBackupType = 'LOG' SET @CurrentCommand += ', NORECOVERY' + IF @Init = 'Y' SET @CurrentCommand += ', INIT' + IF @Format = 'Y' SET @CurrentCommand += ', FORMAT' + IF @BlockSize IS NOT NULL SET @CurrentCommand += ', BLOCKSIZE = ' + CAST(@BlockSize AS nvarchar) + IF @BufferCount IS NOT NULL SET @CurrentCommand += ', BUFFERCOUNT = ' + CAST(@BufferCount AS nvarchar) + IF @CurrentMaxTransferSize IS NOT NULL SET @CurrentCommand += ', MAXTRANSFERSIZE = ' + CAST(@CurrentMaxTransferSize AS nvarchar) + IF @Description IS NOT NULL SET @CurrentCommand += ', DESCRIPTION = N''' + REPLACE(@Description,'''','''''') + '''' + IF @BackupSetName IS NOT NULL SET @CurrentCommand += ', NAME = N''' + REPLACE(@BackupSetName,'''','''''') + '''' + IF @Stats IS NOT NULL SET @CurrentCommand += ', STATS = ' + CAST(@Stats AS nvarchar) + IF @BackupOptions IS NOT NULL SET @CurrentCommand += ', BACKUP_OPTIONS = N''' + REPLACE(@BackupOptions,'''','''''') + '''' + IF @Encrypt = 'Y' SET @CurrentCommand += ', ENCRYPTION (ALGORITHM = ' + UPPER(@EncryptionAlgorithm) + ', ' + IF @Encrypt = 'Y' AND @ServerCertificate IS NOT NULL SET @CurrentCommand += 'SERVER CERTIFICATE = ' + QUOTENAME(@ServerCertificate) + IF @Encrypt = 'Y' AND @ServerAsymmetricKey IS NOT NULL SET @CurrentCommand += 'SERVER ASYMMETRIC KEY = ' + QUOTENAME(@ServerAsymmetricKey) + IF @Encrypt = 'Y' SET @CurrentCommand += ')' + IF @URL IS NOT NULL AND @Credential IS NOT NULL SET @CurrentCommand += ', CREDENTIAL = N''' + REPLACE(@Credential,'''','''''') + '''' + IF @ExpireDate IS NOT NULL SET @CurrentCommand += ', EXPIREDATE = ''' + CONVERT(nvarchar, @ExpireDate, 21) + '''' + IF @RetainDays IS NOT NULL SET @CurrentCommand += ', RETAINDAYS = ' + CAST(@RetainDays AS nvarchar) + END + END IF @BackupSoftware = 'LITESPEED' BEGIN @@ -3658,8 +3901,8 @@ BEGIN END SET @CurrentCommand += ', @with = ''' - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' IF @CurrentBackupType = 'DIFF' SET @CurrentCommand += ', DIFFERENTIAL' IF @CopyOnly = 'Y' SET @CurrentCommand += ', COPY_ONLY' IF @NoRecovery = 'Y' AND @CurrentBackupType = 'LOG' SET @CurrentCommand += ', NORECOVERY' @@ -3676,6 +3919,8 @@ BEGIN IF @Throttle IS NOT NULL SET @CurrentCommand += ', @throttle = ' + CAST(@Throttle AS nvarchar) IF @Description IS NOT NULL SET @CurrentCommand += ', @desc = N''' + REPLACE(@Description,'''','''''') + '''' IF @ObjectLevelRecoveryMap = 'Y' SET @CurrentCommand += ', @olrmap = 1' + IF @ExpireDate IS NOT NULL SET @CurrentCommand += ', @expiration = ''' + CONVERT(nvarchar, @ExpireDate, 21) + '''' + IF @RetainDays IS NOT NULL SET @CurrentCommand += ', @retaindays = ' + CAST(@RetainDays AS nvarchar) IF @EncryptionAlgorithm IS NOT NULL SET @CurrentCommand += ', @cryptlevel = ' + CASE WHEN @EncryptionAlgorithm = 'RC2_40' THEN '0' @@ -3720,8 +3965,8 @@ BEGIN SET @CurrentCommand += ' MIRRORFILE' + ' = N''' + REPLACE((SELECT FilePath FROM @CurrentFiles WHERE Mirror = 1),'''','''''') + ''', ' END - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' IF @CurrentBackupType = 'DIFF' SET @CurrentCommand += ', DIFFERENTIAL' IF @CopyOnly = 'Y' SET @CurrentCommand += ', COPY_ONLY' IF @NoRecovery = 'Y' AND @CurrentBackupType = 'LOG' SET @CurrentCommand += ', NORECOVERY' @@ -3761,7 +4006,7 @@ BEGIN SET @CurrentCommand += ', @backuptype = ' + CASE WHEN @CurrentBackupType = 'FULL' THEN '''Full''' WHEN @CurrentBackupType = 'DIFF' THEN '''Differential''' WHEN @CurrentBackupType = 'LOG' THEN '''Log''' END IF @ReadWriteFileGroups = 'Y' AND @CurrentDatabaseName <> 'master' SET @CurrentCommand += ', @readwritefilegroups = 1' - SET @CurrentCommand += ', @checksum = ' + CASE WHEN @CheckSum = 'Y' THEN '1' WHEN @CheckSum = 'N' THEN '0' END + SET @CurrentCommand += ', @checksum = ' + CASE WHEN @Checksum = 'Y' THEN '1' WHEN @Checksum = 'N' THEN '0' END SET @CurrentCommand += ', @copyonly = ' + CASE WHEN @CopyOnly = 'Y' THEN '1' WHEN @CopyOnly = 'N' THEN '0' END IF @CompressionLevel IS NOT NULL SET @CurrentCommand += ', @compressionlevel = ' + CAST(@CompressionLevel AS nvarchar) IF @Threads IS NOT NULL SET @CurrentCommand += ', @threads = ' + CAST(@Threads AS nvarchar) @@ -3785,7 +4030,7 @@ BEGIN SET @CurrentCommand = 'DECLARE @ReturnCode int EXECUTE @ReturnCode = dbo.emc_run_backup ''' - SET @CurrentCommand += ' -c ' + CASE WHEN @CurrentAvailabilityGroup IS NOT NULL THEN @Cluster ELSE CAST(SERVERPROPERTY('MachineName') AS nvarchar) END + SET @CurrentCommand += ' -c ' + CASE WHEN @Cluster IS NOT NULL AND @CurrentAvailabilityGroup IS NOT NULL THEN @Cluster ELSE CAST(SERVERPROPERTY('MachineName') AS nvarchar) END SET @CurrentCommand += ' -l ' + CASE WHEN @CurrentBackupType = 'FULL' THEN 'full' @@ -3797,7 +4042,7 @@ BEGIN IF @CleanupTime IS NOT NULL SET @CurrentCommand += ' -y +' + CAST(@CleanupTime/24 + CASE WHEN @CleanupTime%24 > 0 THEN 1 ELSE 0 END AS nvarchar) + 'd' - IF @CheckSum = 'Y' SET @CurrentCommand += ' -k' + IF @Checksum = 'Y' SET @CurrentCommand += ' -k' SET @CurrentCommand += ' -S ' + CAST(@CurrentNumberOfFiles AS nvarchar) @@ -3814,9 +4059,11 @@ BEGIN SET @CurrentCommand += ' -a "NSR_SKIP_NON_BACKUPABLE_STATE_DB=TRUE"' SET @CurrentCommand += ' -a "BACKUP_PROMOTION=NONE"' IF @CopyOnly = 'Y' SET @CurrentCommand += ' -a "NSR_COPY_ONLY=TRUE"' + IF @BackupSetName IS NOT NULL SET @CurrentCommand += ' -N "' + REPLACE(@BackupSetName,'''','''''') + '"' - IF SERVERPROPERTY('InstanceName') IS NULL SET @CurrentCommand += ' "MSSQL' + ':' + REPLACE(REPLACE(@CurrentDatabaseName,'''',''''''),'.','\.') + '"' - IF SERVERPROPERTY('InstanceName') IS NOT NULL SET @CurrentCommand += ' "MSSQL$' + CAST(SERVERPROPERTY('InstanceName') AS nvarchar) + ':' + REPLACE(REPLACE(@CurrentDatabaseName,'''',''''''),'.','\.') + '"' + IF SERVERPROPERTY('InstanceName') IS NULL SET @CurrentCommand += ' "MSSQL' + IF SERVERPROPERTY('InstanceName') IS NOT NULL SET @CurrentCommand += ' "MSSQL$' + CAST(SERVERPROPERTY('InstanceName') AS nvarchar) + SET @CurrentCommand += ':' + REPLACE(REPLACE(@CurrentDatabaseName,'''',''''''),'.','\.') + '"' SET @CurrentCommand += '''' @@ -3831,7 +4078,11 @@ BEGIN END -- Verify the backup - IF @CurrentBackupOutput = 0 AND @Verify = 'Y' + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @CurrentBackupOutput = 0 AND @Verify = 'Y' AND @AmazonRDS = 0 + ---------------------------------------------------------------------------------------------------- BEGIN WHILE (1 = 1) BEGIN @@ -3860,8 +4111,9 @@ BEGIN ORDER BY FilePath ASC SET @CurrentCommand += ' WITH ' - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Stats IS NOT NULL SET @CurrentCommand += ', STATS = ' + CAST(@Stats AS nvarchar) IF @BackupOptions IS NOT NULL SET @CurrentCommand += ', RESTORE_OPTIONS = N''' + REPLACE(@BackupOptions,'''','''''') + '''' IF @URL IS NOT NULL AND @Credential IS NOT NULL SET @CurrentCommand += ', CREDENTIAL = N''' + REPLACE(@Credential,'''','''''') + '''' END @@ -3880,8 +4132,8 @@ BEGIN ORDER BY FilePath ASC SET @CurrentCommand += ', @with = ''' - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' SET @CurrentCommand += '''' IF @EncryptionKey IS NOT NULL SET @CurrentCommand += ', @encryptionkey = N''' + REPLACE(@EncryptionKey,'''','''''') + '''' @@ -3902,8 +4154,8 @@ BEGIN ORDER BY FilePath ASC SET @CurrentCommand += ' WITH ' - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' IF @EncryptionKey IS NOT NULL SET @CurrentCommand += ', PASSWORD = N''' + REPLACE(@EncryptionKey,'''','''''') + '''' SET @CurrentCommand = 'DECLARE @ReturnCode int EXECUTE @ReturnCode = dbo.sqlbackup N''-SQL "' + REPLACE(@CurrentCommand,'''','''''') + '"''' + ' IF @ReturnCode <> 0 RAISERROR(''Error verifying SQLBackup backup.'', 16, 1)' @@ -4104,6 +4356,7 @@ BEGIN SET @CurrentDifferentialBaseLSN = NULL SET @CurrentDifferentialBaseIsSnapshot = NULL SET @CurrentLogLSN = NULL + SET @BackupInProcess = NULL SET @CurrentLatestBackup = NULL SET @CurrentDatabaseNameFS = NULL SET @CurrentDirectoryStructure = NULL @@ -4112,6 +4365,7 @@ BEGIN SET @CurrentDate = NULL SET @CurrentDateUTC = NULL SET @CurrentCleanupDate = NULL + SET @CurrentReplicaID = NULL SET @CurrentAvailabilityGroupID = NULL SET @CurrentAvailabilityGroup = NULL @@ -4158,5 +4412,4 @@ BEGIN ---------------------------------------------------------------------------------------------------- END -GO - +GO \ No newline at end of file diff --git a/DatabaseIntegrityCheck.sql b/DatabaseIntegrityCheck.sql index 17f5daad..e01b56ef 100644 --- a/DatabaseIntegrityCheck.sql +++ b/DatabaseIntegrityCheck.sql @@ -15,6 +15,7 @@ ALTER PROCEDURE [dbo].[DatabaseIntegrityCheck] @DataPurity nvarchar(max) = 'N', @NoIndex nvarchar(max) = 'N', @ExtendedLogicalChecks nvarchar(max) = 'N', +@NoInformationalMessages nvarchar(max) = 'N', @TabLock nvarchar(max) = 'N', @FileGroups nvarchar(max) = NULL, @Objects nvarchar(max) = NULL, @@ -39,7 +40,7 @@ BEGIN --// Source: https://ola.hallengren.com //-- --// License: https://ola.hallengren.com/license.html //-- --// GitHub: https://github.com/olahallengren/sql-server-maintenance-solution //-- - --// Version: 2024-12-27 18:10:28 //-- + --// Version: 2025-02-19 21:12:35 //-- ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON @@ -191,7 +192,7 @@ BEGIN SET @HostPlatform = 'Windows' END - DECLARE @AmazonRDS bit = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END + DECLARE @AmazonRDS bit = CASE WHEN SERVERPROPERTY('EngineEdition') IN (5, 8) THEN 0 WHEN EXISTS (SELECT * FROM sys.databases WHERE [name] = 'rdsadmin') AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END ---------------------------------------------------------------------------------------------------- --// Log initial information //-- @@ -203,6 +204,7 @@ BEGIN SET @Parameters += ', @DataPurity = ' + ISNULL('''' + REPLACE(@DataPurity,'''','''''') + '''','NULL') SET @Parameters += ', @NoIndex = ' + ISNULL('''' + REPLACE(@NoIndex,'''','''''') + '''','NULL') SET @Parameters += ', @ExtendedLogicalChecks = ' + ISNULL('''' + REPLACE(@ExtendedLogicalChecks,'''','''''') + '''','NULL') + SET @Parameters += ', @NoInformationalMessages = ' + ISNULL('''' + REPLACE(@NoInformationalMessages,'''','''''') + '''','NULL') SET @Parameters += ', @TabLock = ' + ISNULL('''' + REPLACE(@TabLock,'''','''''') + '''','NULL') SET @Parameters += ', @FileGroups = ' + ISNULL('''' + REPLACE(@FileGroups,'''','''''') + '''','NULL') SET @Parameters += ', @Objects = ' + ISNULL('''' + REPLACE(@Objects,'''','''''') + '''','NULL') @@ -234,7 +236,7 @@ BEGIN SET @StartMessage = 'Platform: ' + @HostPlatform RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT - SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME(DB_ID())) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) + SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME()) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT SET @StartMessage = 'Parameters: ' + @Parameters @@ -252,10 +254,10 @@ BEGIN --// Check core requirements //-- ---------------------------------------------------------------------------------------------------- - IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE database_id = DB_ID()) >= 90 + IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE [name] = DB_NAME()) >= 90 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The database ' + QUOTENAME(DB_NAME(DB_ID())) + ' has to be in compatibility level 90 or higher.', 16, 1 + SELECT 'The database ' + QUOTENAME(DB_NAME()) + ' has to be in compatibility level 90 or higher.', 16, 1 END IF NOT (SELECT uses_ansi_nulls FROM sys.sql_modules WHERE [object_id] = @@PROCID) = 1 @@ -750,6 +752,13 @@ BEGIN ---------------------------------------------------------------------------------------------------- + IF @NoInformationalMessages NOT IN ('Y','N') OR @NoInformationalMessages IS NULL + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @NoInformationalMessages is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- IF @TabLock NOT IN ('Y','N') OR @TabLock IS NULL BEGIN INSERT INTO @Errors ([Message], Severity, [State]) @@ -1355,8 +1364,8 @@ BEGIN SET @DatabaseMessage = 'Recovery model: ' + @CurrentRecoveryModel RAISERROR('%s',10,1,@DatabaseMessage) WITH NOWAIT END - - IF @Version >= 11 AND SERVERPROPERTY('IsHadrEnabled') = 1 + + IF @Version >= 11 AND SERVERPROPERTY('IsHadrEnabled') = 1 BEGIN SELECT @CurrentReplicaID = databases.replica_id FROM sys.databases databases @@ -1386,11 +1395,12 @@ BEGIN IF SERVERPROPERTY('EngineEdition') <> 5 BEGIN SELECT @CurrentDatabaseMirroringRole = UPPER(mirroring_role_desc) - FROM sys.database_mirroring - WHERE database_id = DB_ID(@CurrentDatabaseName) + FROM sys.database_mirroring database_mirroring + INNER JOIN sys.databases databases ON database_mirroring.database_id = databases.database_id + WHERE databases.[name] = @CurrentDatabaseName END - - IF @CurrentAvailabilityGroup IS NOT NULL + + IF @CurrentAvailabilityGroup IS NOT NULL BEGIN SET @DatabaseMessage = 'Availability group: ' + ISNULL(@CurrentAvailabilityGroup,'N/A') RAISERROR('%s',10,1,@DatabaseMessage) WITH NOWAIT @@ -1428,6 +1438,7 @@ BEGIN AND ((@AvailabilityGroupReplicas = 'PRIMARY' AND @CurrentAvailabilityGroupRole = 'PRIMARY') OR (@AvailabilityGroupReplicas = 'SECONDARY' AND @CurrentAvailabilityGroupRole = 'SECONDARY') OR (@AvailabilityGroupReplicas = 'PREFERRED_BACKUP_REPLICA' AND @CurrentIsPreferredBackupReplica = 1) OR @AvailabilityGroupReplicas = 'ALL' OR @CurrentAvailabilityGroupRole IS NULL) AND NOT (@CurrentIsReadOnly = 1 AND @Updateability = 'READ_WRITE') AND NOT (@CurrentIsReadOnly = 0 AND @Updateability = 'READ_ONLY') + AND NOT (@AmazonRDS = 1 AND @CurrentDatabaseName = 'rdsadmin') BEGIN -- Check database @@ -1441,10 +1452,11 @@ BEGIN IF @LockTimeout IS NOT NULL SET @CurrentCommand = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand += 'DBCC CHECKDB (' + QUOTENAME(@CurrentDatabaseName) IF @NoIndex = 'Y' SET @CurrentCommand += ', NOINDEX' - SET @CurrentCommand += ') WITH NO_INFOMSGS, ALL_ERRORMSGS' + SET @CurrentCommand += ') WITH ALL_ERRORMSGS' IF @DataPurity = 'Y' SET @CurrentCommand += ', DATA_PURITY' IF @PhysicalOnly = 'Y' SET @CurrentCommand += ', PHYSICAL_ONLY' IF @ExtendedLogicalChecks = 'Y' SET @CurrentCommand += ', EXTENDED_LOGICAL_CHECKS' + IF @NoInformationalMessages = 'Y' SET @CurrentCommand += ', NO_INFOMSGS' IF @TabLock = 'Y' SET @CurrentCommand += ', TABLOCK' IF @MaxDOP IS NOT NULL SET @CurrentCommand += ', MAXDOP = ' + CAST(@MaxDOP AS nvarchar) @@ -1569,8 +1581,9 @@ BEGIN IF @LockTimeout IS NOT NULL SET @CurrentCommand = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand += 'DBCC CHECKFILEGROUP (' + QUOTENAME(@CurrentFileGroupName) IF @NoIndex = 'Y' SET @CurrentCommand += ', NOINDEX' - SET @CurrentCommand += ') WITH NO_INFOMSGS, ALL_ERRORMSGS' + SET @CurrentCommand += ') WITH ALL_ERRORMSGS' IF @PhysicalOnly = 'Y' SET @CurrentCommand += ', PHYSICAL_ONLY' + IF @NoInformationalMessages = 'Y' SET @CurrentCommand += ', NO_INFOMSGS' IF @TabLock = 'Y' SET @CurrentCommand += ', TABLOCK' IF @MaxDOP IS NOT NULL SET @CurrentCommand += ', MAXDOP = ' + CAST(@MaxDOP AS nvarchar) @@ -1608,7 +1621,8 @@ BEGIN SET @CurrentCommand = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand += 'DBCC CHECKALLOC (' + QUOTENAME(@CurrentDatabaseName) - SET @CurrentCommand += ') WITH NO_INFOMSGS, ALL_ERRORMSGS' + SET @CurrentCommand += ') WITH ALL_ERRORMSGS' + IF @NoInformationalMessages = 'Y' SET @CurrentCommand += ', NO_INFOMSGS' IF @TabLock = 'Y' SET @CurrentCommand += ', TABLOCK' EXECUTE @CurrentCommandOutput = dbo.CommandExecute @DatabaseContext = @CurrentDatabaseContext, @Command = @CurrentCommand, @CommandType = @CurrentCommandType, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute @@ -1736,10 +1750,11 @@ BEGIN IF @LockTimeout IS NOT NULL SET @CurrentCommand = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand += 'DBCC CHECKTABLE (' + QUOTENAME(QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName),'''') IF @NoIndex = 'Y' SET @CurrentCommand += ', NOINDEX' - SET @CurrentCommand += ') WITH NO_INFOMSGS, ALL_ERRORMSGS' + SET @CurrentCommand += ') WITH ALL_ERRORMSGS' IF @DataPurity = 'Y' SET @CurrentCommand += ', DATA_PURITY' IF @PhysicalOnly = 'Y' SET @CurrentCommand += ', PHYSICAL_ONLY' IF @ExtendedLogicalChecks = 'Y' SET @CurrentCommand += ', EXTENDED_LOGICAL_CHECKS' + IF @NoInformationalMessages = 'Y' SET @CurrentCommand += ', NO_INFOMSGS' IF @TabLock = 'Y' SET @CurrentCommand += ', TABLOCK' IF @MaxDOP IS NOT NULL SET @CurrentCommand += ', MAXDOP = ' + CAST(@MaxDOP AS nvarchar) @@ -1780,7 +1795,8 @@ BEGIN SET @CurrentCommand = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand += 'DBCC CHECKCATALOG (' + QUOTENAME(@CurrentDatabaseName) - SET @CurrentCommand += ') WITH NO_INFOMSGS' + SET @CurrentCommand += ')' + IF @NoInformationalMessages = 'Y' SET @CurrentCommand += ' WITH NO_INFOMSGS' EXECUTE @CurrentCommandOutput = dbo.CommandExecute @DatabaseContext = @CurrentDatabaseContext, @Command = @CurrentCommand, @CommandType = @CurrentCommandType, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute SET @Error = @@ERROR @@ -1865,5 +1881,12 @@ BEGIN END +GO + END + + ---------------------------------------------------------------------------------------------------- + +END + GO diff --git a/IndexOptimize.sql b/IndexOptimize.sql index b34626ca..71b7e0c2 100644 --- a/IndexOptimize.sql +++ b/IndexOptimize.sql @@ -2,6 +2,10 @@ GO SET QUOTED_IDENTIFIER ON GO +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[IndexOptimize]') AND type in (N'P', N'PC')) BEGIN EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[IndexOptimize] AS' @@ -53,7 +57,7 @@ BEGIN --// Source: https://ola.hallengren.com //-- --// License: https://ola.hallengren.com/license.html //-- --// GitHub: https://github.com/olahallengren/sql-server-maintenance-solution //-- - --// Version: 2024-12-27 18:10:28 //-- + --// Version: 2025-02-19 21:12:35 //-- ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON @@ -137,10 +141,12 @@ BEGIN DECLARE @CurrentIsImageText bit DECLARE @CurrentIsNewLOB bit DECLARE @CurrentIsFileStream bit - DECLARE @CurrentIsColumnStore bit + DECLARE @CurrentHasColumnstore bit DECLARE @CurrentIsComputed bit + DECLARE @CurrentIsClusteredIndexComputed bit DECLARE @CurrentIsTimestamp bit DECLARE @CurrentAllowPageLocks bit + DECLARE @CurrentHasFilter bit DECLARE @CurrentNoRecompute bit DECLARE @CurrentIsIncremental bit DECLARE @CurrentRowCount bigint @@ -187,11 +193,13 @@ BEGIN IndexName nvarchar(max), IndexType int, AllowPageLocks bit, + HasFilter bit, IsImageText bit, IsNewLOB bit, IsFileStream bit, - IsColumnStore bit, + HasColumnstore bit, IsComputed bit, + IsClusteredIndexComputed bit, IsTimestamp bit, OnReadOnlyFileGroup bit, ResumableIndexOperation bit, @@ -270,7 +278,7 @@ BEGIN SET @HostPlatform = 'Windows' END - DECLARE @AmazonRDS bit = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END + DECLARE @AmazonRDS bit = CASE WHEN SERVERPROPERTY('EngineEdition') IN (5, 8) THEN 0 WHEN EXISTS (SELECT * FROM sys.databases WHERE [name] = 'rdsadmin') AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END ---------------------------------------------------------------------------------------------------- --// Log initial information //-- @@ -327,7 +335,7 @@ BEGIN SET @StartMessage = 'Platform: ' + @HostPlatform RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT - SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME(DB_ID())) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) + SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME()) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT SET @StartMessage = 'Parameters: ' + @Parameters @@ -345,10 +353,10 @@ BEGIN --// Check core requirements //-- ---------------------------------------------------------------------------------------------------- - IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE database_id = DB_ID()) >= 90 + IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE [name] = DB_NAME()) >= 90 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The database ' + QUOTENAME(DB_NAME(DB_ID())) + ' has to be in compatibility level 90 or higher.', 16, 1 + SELECT 'The database ' + QUOTENAME(DB_NAME()) + ' has to be in compatibility level 90 or higher.', 16, 1 END IF NOT (SELECT uses_ansi_nulls FROM sys.sql_modules WHERE [object_id] = @@PROCID) = 1 @@ -1429,15 +1437,15 @@ BEGIN SET @CurrentDatabase_sp_executesql = QUOTENAME(@CurrentDatabaseName) + '.sys.sp_executesql' - IF @ExecuteAsUser IS NOT NULL + BEGIN - SET @CurrentCommand = '' - SET @CurrentCommand += 'IF EXISTS(SELECT * FROM sys.database_principals database_principals WHERE database_principals.[name] = @ParamExecuteAsUser) BEGIN SET @ParamExecuteAsUserExists = 1 END ELSE BEGIN SET @ParamExecuteAsUserExists = 0 END' + + - EXECUTE @CurrentDatabase_sp_executesql @stmt = @CurrentCommand, @params = N'@ParamExecuteAsUser sysname, @ParamExecuteAsUserExists bit OUTPUT', @ParamExecuteAsUser = @ExecuteAsUser, @ParamExecuteAsUserExists = @CurrentExecuteAsUserExists OUTPUT - END + + - BEGIN + SET @DatabaseMessage = 'Date and time: ' + CONVERT(nvarchar,SYSDATETIME(),120) RAISERROR('%s',10,1,@DatabaseMessage) WITH NOWAIT @@ -1493,8 +1501,9 @@ BEGIN IF SERVERPROPERTY('EngineEdition') <> 5 BEGIN SELECT @CurrentDatabaseMirroringRole = UPPER(mirroring_role_desc) - FROM sys.database_mirroring - WHERE database_id = DB_ID(@CurrentDatabaseName) + FROM sys.database_mirroring database_mirroring + INNER JOIN sys.databases databases ON database_mirroring.database_id = databases.database_id + WHERE databases.[name] = @CurrentDatabaseName END IF @CurrentAvailabilityGroup IS NOT NULL @@ -1513,7 +1522,17 @@ BEGIN END RAISERROR(@EmptyLine,10,1) WITH NOWAIT + IF @ExecuteAsUser IS NOT NULL + AND @CurrentDatabaseState = 'ONLINE' + AND NOT (@CurrentUserAccess = 'SINGLE_USER') + AND NOT (@CurrentAvailabilityGroup IS NOT NULL AND (@CurrentAvailabilityGroupRole <> 'PRIMARY' OR @CurrentAvailabilityGroupRole IS NULL)) + AND NOT (@AmazonRDS = 1 AND @CurrentDatabaseName = 'rdsadmin') + BEGIN + SET @CurrentCommand = '' + SET @CurrentCommand += 'IF EXISTS(SELECT * FROM sys.database_principals database_principals WHERE database_principals.[name] = @ParamExecuteAsUser) BEGIN SET @ParamExecuteAsUserExists = 1 END ELSE BEGIN SET @ParamExecuteAsUserExists = 0 END' + EXECUTE @CurrentDatabase_sp_executesql @stmt = @CurrentCommand, @params = N'@ParamExecuteAsUser sysname, @ParamExecuteAsUserExists bit OUTPUT', @ParamExecuteAsUser = @ExecuteAsUser, @ParamExecuteAsUserExists = @CurrentExecuteAsUserExists OUTPUT + END IF @CurrentExecuteAsUserExists = 0 BEGIN SET @DatabaseMessage = 'The user ' + QUOTENAME(@ExecuteAsUser) + ' does not exist in the database ' + QUOTENAME(@CurrentDatabaseName) + '.' @@ -1524,6 +1543,8 @@ BEGIN IF @CurrentDatabaseState = 'ONLINE' AND NOT (@CurrentUserAccess = 'SINGLE_USER') AND NOT (@CurrentAvailabilityGroup IS NOT NULL AND (@CurrentAvailabilityGroupRole <> 'PRIMARY' OR @CurrentAvailabilityGroupRole IS NULL)) + AND NOT (@AmazonRDS = 1 AND @CurrentDatabaseName = 'rdsadmin') + AND NOT (@CurrentIsReadOnly = 1) AND (@CurrentExecuteAsUserExists = 1 OR @CurrentExecuteAsUserExists IS NULL) BEGIN @@ -1531,7 +1552,7 @@ BEGIN IF (EXISTS(SELECT * FROM @ActionsPreferred) OR @UpdateStatistics IS NOT NULL) AND (SYSDATETIME() < DATEADD(SECOND,@TimeLimit,@StartTime) OR @TimeLimit IS NULL) BEGIN SET @CurrentCommand = 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;' - + ' SELECT SchemaID, SchemaName, ObjectID, ObjectName, ObjectType, IsMemoryOptimized, IndexID, IndexName, IndexType, AllowPageLocks, IsImageText, IsNewLOB, IsFileStream, IsColumnStore, IsComputed, IsTimestamp, OnReadOnlyFileGroup, ResumableIndexOperation, StatisticsID, StatisticsName, NoRecompute, IsIncremental, PartitionID, PartitionNumber, PartitionCount, [Order], Selected, Completed' + + ' SELECT SchemaID, SchemaName, ObjectID, ObjectName, ObjectType, IsMemoryOptimized, IndexID, IndexName, IndexType, AllowPageLocks, HasFilter, IsImageText, IsNewLOB, IsFileStream, HasColumnstore, IsComputed, IsClusteredIndexComputed, IsTimestamp, OnReadOnlyFileGroup, ResumableIndexOperation, StatisticsID, StatisticsName, NoRecompute, IsIncremental, PartitionID, PartitionNumber, PartitionCount, [Order], Selected, Completed' + ' FROM (' IF EXISTS(SELECT * FROM @ActionsPreferred) OR @UpdateStatistics IN('ALL','INDEX') @@ -1546,6 +1567,7 @@ BEGIN + ', indexes.[name] AS IndexName' + ', indexes.[type] AS IndexType' + ', indexes.allow_page_locks AS AllowPageLocks' + + ', indexes.has_filter AS HasFilter' + ', CASE WHEN indexes.[type] = 1 AND EXISTS(SELECT * FROM sys.columns columns INNER JOIN sys.types types ON columns.system_type_id = types.user_type_id WHERE columns.[object_id] = objects.object_id AND types.name IN(''image'',''text'',''ntext'')) THEN 1 ELSE 0 END AS IsImageText' @@ -1554,17 +1576,18 @@ BEGIN + ', CASE WHEN indexes.[type] = 1 AND EXISTS(SELECT * FROM sys.columns columns WHERE columns.[object_id] = objects.object_id AND columns.is_filestream = 1) THEN 1 ELSE 0 END AS IsFileStream' - + ', CASE WHEN EXISTS(SELECT * FROM sys.indexes indexes WHERE indexes.[object_id] = objects.object_id AND [type] IN(5,6)) THEN 1 ELSE 0 END AS IsColumnStore' + + ', CASE WHEN EXISTS(SELECT * FROM sys.indexes indexes WHERE indexes.[object_id] = objects.object_id AND [type] IN(5,6)) THEN 1 ELSE 0 END AS HasColumnstore' + ', CASE WHEN EXISTS(SELECT * FROM sys.index_columns index_columns INNER JOIN sys.columns columns ON index_columns.object_id = columns.object_id AND index_columns.column_id = columns.column_id WHERE (index_columns.key_ordinal > 0 OR index_columns.partition_ordinal > 0) AND columns.is_computed = 1 AND index_columns.object_id = indexes.object_id AND index_columns.index_id = indexes.index_id) THEN 1 ELSE 0 END AS IsComputed' + + ', CASE WHEN EXISTS(SELECT * FROM sys.index_columns index_columns INNER JOIN sys.columns columns ON index_columns.object_id = columns.object_id AND index_columns.column_id = columns.column_id INNER JOIN sys.indexes indexes2 ON index_columns.object_id = indexes2.object_id AND index_columns.index_id = indexes2.index_id WHERE (index_columns.key_ordinal > 0 OR index_columns.partition_ordinal > 0) AND columns.is_computed = 1 AND indexes2.[type] = 1 AND index_columns.object_id = indexes.object_id) THEN 1 ELSE 0 END AS IsClusteredIndexComputed' + ', CASE WHEN EXISTS(SELECT * FROM sys.index_columns index_columns INNER JOIN sys.columns columns ON index_columns.[object_id] = columns.[object_id] AND index_columns.column_id = columns.column_id INNER JOIN sys.types types ON columns.system_type_id = types.system_type_id WHERE index_columns.[object_id] = objects.object_id AND index_columns.index_id = indexes.index_id AND types.[name] = ''timestamp'') THEN 1 ELSE 0 END AS IsTimestamp' + ', CASE WHEN EXISTS (SELECT * FROM sys.indexes indexes2 INNER JOIN sys.destination_data_spaces destination_data_spaces ON indexes.data_space_id = destination_data_spaces.partition_scheme_id INNER JOIN sys.filegroups filegroups ON destination_data_spaces.data_space_id = filegroups.data_space_id WHERE filegroups.is_read_only = 1 AND indexes2.[object_id] = indexes.[object_id] AND indexes2.[index_id] = indexes.index_id' + CASE WHEN @PartitionLevel = 'Y' THEN ' AND destination_data_spaces.destination_id = partitions.partition_number' ELSE '' END + ') THEN 1' + ' WHEN EXISTS (SELECT * FROM sys.indexes indexes2 INNER JOIN sys.filegroups filegroups ON indexes.data_space_id = filegroups.data_space_id WHERE filegroups.is_read_only = 1 AND indexes.[object_id] = indexes2.[object_id] AND indexes.[index_id] = indexes2.index_id) THEN 1' + ' WHEN indexes.[type] = 1 AND EXISTS (SELECT * FROM sys.tables tables INNER JOIN sys.filegroups filegroups ON tables.lob_data_space_id = filegroups.data_space_id WHERE filegroups.is_read_only = 1 AND tables.[object_id] = objects.[object_id]) THEN 1 ELSE 0 END AS OnReadOnlyFileGroup' - + ', ' + CASE WHEN @Version >= 14 THEN 'CASE WHEN EXISTS(SELECT * FROM sys.index_resumable_operations index_resumable_operations WHERE state_desc = ''PAUSED'' AND index_resumable_operations.object_id = indexes.object_id AND index_resumable_operations.index_id = indexes.index_id AND (index_resumable_operations.partition_number = partitions.partition_number OR index_resumable_operations.partition_number IS NULL)) THEN 1 ELSE 0 END' ELSE '0' END + ' AS ResumableIndexOperation' + + ', ' + CASE WHEN @Version >= 14 OR SERVERPROPERTY('EngineEdition') IN (5, 8) THEN 'CASE WHEN EXISTS(SELECT * FROM sys.index_resumable_operations index_resumable_operations WHERE state_desc = ''PAUSED'' AND index_resumable_operations.object_id = indexes.object_id AND index_resumable_operations.index_id = indexes.index_id' + CASE WHEN @PartitionLevel = 'Y' THEN ' AND (index_resumable_operations.partition_number = partitions.partition_number OR index_resumable_operations.partition_number IS NULL)' ELSE '' END + ') THEN 1 ELSE 0 END' ELSE '0' END + ' AS ResumableIndexOperation' + ', stats.stats_id AS StatisticsID' + ', stats.name AS StatisticsName' @@ -1609,11 +1632,13 @@ BEGIN + ', NULL AS IndexID, NULL AS IndexName' + ', NULL AS IndexType' + ', NULL AS AllowPageLocks' + + ', NULL AS HasFilter' + ', NULL AS IsImageText' + ', NULL AS IsNewLOB' + ', NULL AS IsFileStream' - + ', NULL AS IsColumnStore' + + ', NULL AS HasColumnstore' + ', NULL AS IsComputed' + + ', NULL AS IsClusteredIndexComputed' + ', NULL AS IsTimestamp' + ', NULL AS OnReadOnlyFileGroup' + ', NULL AS ResumableIndexOperation' @@ -1638,13 +1663,59 @@ BEGIN END SET @CurrentCommand = @CurrentCommand + ' WHERE objects.[type] IN(''U'',''V'')' + + CASE WHEN @Version >= 12 THEN ' AND (tables.is_memory_optimized = 0 OR tables.is_memory_optimized IS NULL)' ELSE '' END + CASE WHEN @MSShippedObjects = 'N' THEN ' AND objects.is_ms_shipped = 0' ELSE '' END + ' AND NOT EXISTS(SELECT * FROM sys.indexes indexes WHERE indexes.[object_id] = stats.[object_id] AND indexes.index_id = stats.stats_id)' + + ' AND NOT EXISTS(SELECT * FROM sys.indexes indexes2 WHERE indexes2.[object_id] = stats.[object_id] AND indexes2.type = 1 AND indexes2.is_disabled = 1)' + + IF @Version >= 12 + BEGIN + SET @CurrentCommand = @CurrentCommand + ' UNION ' + + SET @CurrentCommand = @CurrentCommand + 'SELECT schemas.[schema_id] AS SchemaID' + + ', schemas.[name] AS SchemaName' + + ', objects.[object_id] AS ObjectID' + + ', objects.[name] AS ObjectName' + + ', RTRIM(objects.[type]) AS ObjectType' + + ', tables.is_memory_optimized AS IsMemoryOptimized' + + ', NULL AS IndexID, NULL AS IndexName' + + ', NULL AS IndexType' + + ', NULL AS AllowPageLocks' + + ', NULL AS HasFilter' + + ', NULL AS IsImageText' + + ', NULL AS IsNewLOB' + + ', NULL AS IsFileStream' + + ', NULL AS HasColumnstore' + + ', NULL AS IsComputed' + + ', NULL AS IsClusteredIndexComputed' + + ', NULL AS IsTimestamp' + + ', NULL AS OnReadOnlyFileGroup' + + ', NULL AS ResumableIndexOperation' + + ', stats.stats_id AS StatisticsID' + + ', stats.name AS StatisticsName' + + ', stats.no_recompute AS NoRecompute' + + ', ' + CASE WHEN @Version >= 12 THEN 'stats.is_incremental' ELSE '0' END + ' AS IsIncremental' + + ', NULL AS PartitionID' + + ', NULL AS PartitionNumber' + + ', NULL AS PartitionCount' + + ', 0 AS [Order]' + + ', 0 AS Selected' + + ', 0 AS Completed' + + ' FROM sys.stats stats' + + ' INNER JOIN sys.objects objects ON stats.[object_id] = objects.[object_id]' + + ' INNER JOIN sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id]' + + ' INNER JOIN sys.tables tables ON objects.[object_id] = tables.[object_id]' + + SET @CurrentCommand = @CurrentCommand + ' WHERE objects.[type] = ''U''' + + ' AND tables.is_memory_optimized = 1' + + CASE WHEN @MSShippedObjects = 'N' THEN ' AND objects.is_ms_shipped = 0' ELSE '' END + + ' AND NOT EXISTS(SELECT * FROM sys.indexes indexes WHERE indexes.[object_id] = stats.[object_id] AND indexes.index_id = stats.stats_id)' + END END SET @CurrentCommand = @CurrentCommand + ') IndexesStatistics' - INSERT INTO @tmpIndexesStatistics (SchemaID, SchemaName, ObjectID, ObjectName, ObjectType, IsMemoryOptimized, IndexID, IndexName, IndexType, AllowPageLocks, IsImageText, IsNewLOB, IsFileStream, IsColumnStore, IsComputed, IsTimestamp, OnReadOnlyFileGroup, ResumableIndexOperation, StatisticsID, StatisticsName, [NoRecompute], IsIncremental, PartitionID, PartitionNumber, PartitionCount, [Order], Selected, Completed) + INSERT INTO @tmpIndexesStatistics (SchemaID, SchemaName, ObjectID, ObjectName, ObjectType, IsMemoryOptimized, IndexID, IndexName, IndexType, AllowPageLocks, HasFilter, IsImageText, IsNewLOB, IsFileStream, HasColumnstore, IsComputed, IsClusteredIndexComputed, IsTimestamp, OnReadOnlyFileGroup, ResumableIndexOperation, StatisticsID, StatisticsName, [NoRecompute], IsIncremental, PartitionID, PartitionNumber, PartitionCount, [Order], Selected, Completed) EXECUTE @CurrentDatabase_sp_executesql @stmt = @CurrentCommand SET @Error = @@ERROR IF @Error <> 0 @@ -1744,11 +1815,13 @@ BEGIN @CurrentIndexName = IndexName, @CurrentIndexType = IndexType, @CurrentAllowPageLocks = AllowPageLocks, + @CurrentHasFilter = HasFilter, @CurrentIsImageText = IsImageText, @CurrentIsNewLOB = IsNewLOB, @CurrentIsFileStream = IsFileStream, - @CurrentIsColumnStore = IsColumnStore, + @CurrentHasColumnstore = HasColumnstore, @CurrentIsComputed = IsComputed, + @CurrentIsClusteredIndexComputed = IsClusteredIndexComputed, @CurrentIsTimestamp = IsTimestamp, @CurrentOnReadOnlyFileGroup = OnReadOnlyFileGroup, @CurrentResumableIndexOperation = ResumableIndexOperation, @@ -1886,6 +1959,7 @@ BEGIN AND @CurrentOnReadOnlyFileGroup = 0 AND EXISTS(SELECT * FROM @ActionsPreferred) AND (EXISTS(SELECT [Priority], [Action], COUNT(*) FROM @ActionsPreferred GROUP BY [Priority], [Action] HAVING COUNT(*) <> 3) OR @MinNumberOfPages > 0 OR @MaxNumberOfPages IS NOT NULL) + AND NOT (SERVERPROPERTY('EngineEdition') = 8 AND @CurrentDatabaseName IN ('master', 'model')) BEGIN SET @CurrentCommand = '' @@ -1924,25 +1998,33 @@ BEGIN -- Which actions are allowed? IF @CurrentIndexID IS NOT NULL AND EXISTS(SELECT * FROM @ActionsPreferred) BEGIN - IF @CurrentOnReadOnlyFileGroup = 0 AND @CurrentIndexType IN (1,2,3,4,5) AND (@CurrentIsMemoryOptimized = 0 OR @CurrentIsMemoryOptimized IS NULL) AND (@CurrentAllowPageLocks = 1 OR @CurrentIndexType = 5) + IF NOT (@CurrentOnReadOnlyFileGroup = 1) + AND NOT (@CurrentIsMemoryOptimized = 1) + AND NOT (@CurrentAllowPageLocks = 0) BEGIN INSERT INTO @CurrentActionsAllowed ([Action]) VALUES ('INDEX_REORGANIZE') END - IF @CurrentOnReadOnlyFileGroup = 0 AND @CurrentIndexType IN (1,2,3,4,5) AND (@CurrentIsMemoryOptimized = 0 OR @CurrentIsMemoryOptimized IS NULL) + IF NOT (@CurrentOnReadOnlyFileGroup = 1) + AND NOT (@CurrentIsMemoryOptimized = 1) BEGIN INSERT INTO @CurrentActionsAllowed ([Action]) VALUES ('INDEX_REBUILD_OFFLINE') END - IF @CurrentOnReadOnlyFileGroup = 0 - AND (@CurrentIsMemoryOptimized = 0 OR @CurrentIsMemoryOptimized IS NULL) - AND (@CurrentIsPartition = 0 OR @Version >= 12) - AND ((@CurrentIndexType = 1 AND @CurrentIsImageText = 0 AND @CurrentIsNewLOB = 0) - OR (@CurrentIndexType = 2 AND @CurrentIsNewLOB = 0) - OR (@CurrentIndexType = 1 AND @CurrentIsImageText = 0 AND @CurrentIsFileStream = 0 AND @Version >= 11) - OR (@CurrentIndexType = 2 AND @Version >= 11)) - AND (@CurrentIsColumnStore = 0 OR @Version < 11) - AND SERVERPROPERTY('EngineEdition') IN (3,5,8) + IF SERVERPROPERTY('EngineEdition') IN (3, 5, 8) + AND NOT (@CurrentOnReadOnlyFileGroup = 1) + AND NOT (@CurrentIsMemoryOptimized = 1) + AND NOT (@CurrentIsPartition = 1 AND @Version < 12) + AND NOT (@CurrentIndexType = 1 AND @CurrentIsImageText = 1) + AND NOT (@CurrentIndexType = 1 AND @CurrentIsFileStream = 1) + AND NOT (@CurrentIndexType = 1 AND @CurrentIsNewLOB = 1 AND @Version < 11) + AND NOT (@CurrentIndexType = 2 AND @CurrentIsNewLOB = 1 AND @Version < 11) + AND NOT (@CurrentIndexType = 3) + AND NOT (@CurrentIndexType = 4) + AND NOT (@CurrentIndexType = 5 AND @Version < 15) + AND NOT (@CurrentIndexType = 6 AND @Version < 15) + AND NOT (@CurrentIndexType = 1 AND @CurrentHasColumnstore = 1 AND @Version < 13) + AND NOT (@CurrentIndexType = 2 AND @CurrentHasColumnstore = 1 AND @Version < 13) BEGIN INSERT INTO @CurrentActionsAllowed ([Action]) VALUES ('INDEX_REBUILD_ONLINE') @@ -2030,9 +2112,11 @@ BEGIN SET @CurrentComment += 'ImageText: ' + CASE WHEN @CurrentIsImageText = 1 THEN 'Yes' WHEN @CurrentIsImageText = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment += 'NewLOB: ' + CASE WHEN @CurrentIsNewLOB = 1 THEN 'Yes' WHEN @CurrentIsNewLOB = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment += 'FileStream: ' + CASE WHEN @CurrentIsFileStream = 1 THEN 'Yes' WHEN @CurrentIsFileStream = 0 THEN 'No' ELSE 'N/A' END + ', ' - IF @Version >= 11 SET @CurrentComment += 'ColumnStore: ' + CASE WHEN @CurrentIsColumnStore = 1 THEN 'Yes' WHEN @CurrentIsColumnStore = 0 THEN 'No' ELSE 'N/A' END + ', ' + IF @Version >= 11 SET @CurrentComment += 'HasColumnStore: ' + CASE WHEN @CurrentHasColumnstore = 1 THEN 'Yes' WHEN @CurrentHasColumnstore = 0 THEN 'No' ELSE 'N/A' END + ', ' IF @Version >= 14 AND @Resumable = 'Y' SET @CurrentComment += 'Computed: ' + CASE WHEN @CurrentIsComputed = 1 THEN 'Yes' WHEN @CurrentIsComputed = 0 THEN 'No' ELSE 'N/A' END + ', ' + IF @Version >= 14 AND @Resumable = 'Y' AND @CurrentIndexType = 2 SET @CurrentComment += 'ClusteredIndexComputed: ' + CASE WHEN @CurrentIsClusteredIndexComputed = 1 THEN 'Yes' WHEN @CurrentIsClusteredIndexComputed = 0 THEN 'No' ELSE 'N/A' END + ', ' IF @Version >= 14 AND @Resumable = 'Y' SET @CurrentComment += 'Timestamp: ' + CASE WHEN @CurrentIsTimestamp = 1 THEN 'Yes' WHEN @CurrentIsTimestamp = 0 THEN 'No' ELSE 'N/A' END + ', ' + IF @Version >= 14 AND @Resumable = 'Y' SET @CurrentComment += 'HasFilter: ' + CASE WHEN @CurrentHasFilter = 1 THEN 'Yes' WHEN @CurrentHasFilter = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment += 'AllowPageLocks: ' + CASE WHEN @CurrentAllowPageLocks = 1 THEN 'Yes' WHEN @CurrentAllowPageLocks = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment += 'PageCount: ' + ISNULL(CAST(@CurrentPageCount AS nvarchar),'N/A') + ', ' SET @CurrentComment += 'Fragmentation: ' + ISNULL(CAST(@CurrentFragmentationLevel AS nvarchar),'N/A') @@ -2105,10 +2189,10 @@ BEGIN IF (@Version >= 14 OR SERVERPROPERTY('EngineEdition') IN (5,8)) AND @CurrentAction = 'INDEX_REBUILD_ONLINE' AND @CurrentResumableIndexOperation = 0 BEGIN INSERT INTO @CurrentAlterIndexWithClauseArguments (Argument) - SELECT CASE WHEN @Resumable = 'Y' AND @CurrentIndexType IN(1,2) AND @CurrentIsComputed = 0 AND @CurrentIsTimestamp = 0 THEN 'RESUMABLE = ON' ELSE 'RESUMABLE = OFF' END + SELECT CASE WHEN @Resumable = 'Y' AND @CurrentIndexType IN(1,2) AND @CurrentIsComputed = 0 AND @CurrentIsClusteredIndexComputed = 0 AND @CurrentIsTimestamp = 0 AND @CurrentHasFilter = 0 THEN 'RESUMABLE = ON' ELSE 'RESUMABLE = OFF' END END - IF (@Version >= 14 OR SERVERPROPERTY('EngineEdition') IN (5,8)) AND @CurrentAction = 'INDEX_REBUILD_ONLINE' AND @CurrentResumableIndexOperation = 0 AND @Resumable = 'Y' AND @CurrentIndexType IN(1,2) AND @CurrentIsComputed = 0 AND @CurrentIsTimestamp = 0 AND @TimeLimit IS NOT NULL + IF (@Version >= 14 OR SERVERPROPERTY('EngineEdition') IN (5,8)) AND @CurrentAction = 'INDEX_REBUILD_ONLINE' AND @Resumable = 'Y' AND @CurrentIndexType IN(1,2) AND @CurrentIsComputed = 0 AND @CurrentIsClusteredIndexComputed = 0 AND @CurrentIsTimestamp = 0 AND @CurrentHasFilter = 0 AND @TimeLimit IS NOT NULL BEGIN INSERT INTO @CurrentAlterIndexWithClauseArguments (Argument) SELECT 'MAX_DURATION = ' + CAST(DATEDIFF(MINUTE,SYSDATETIME(),DATEADD(SECOND,@TimeLimit,@StartTime)) AS nvarchar(max)) @@ -2220,16 +2304,16 @@ BEGIN SELECT 'SAMPLE ' + CAST(@CurrentStatisticsSample AS nvarchar) + ' PERCENT' END - IF @CurrentStatisticsResample = 'Y' + IF @CurrentNoRecompute = 1 BEGIN INSERT INTO @CurrentUpdateStatisticsWithClauseArguments (Argument) - SELECT 'RESAMPLE' + SELECT 'NORECOMPUTE' END - IF @CurrentNoRecompute = 1 + IF @CurrentStatisticsResample = 'Y' BEGIN INSERT INTO @CurrentUpdateStatisticsWithClauseArguments (Argument) - SELECT 'NORECOMPUTE' + SELECT 'RESAMPLE' END IF EXISTS (SELECT * FROM @CurrentUpdateStatisticsWithClauseArguments) @@ -2310,10 +2394,12 @@ BEGIN SET @CurrentIsImageText = NULL SET @CurrentIsNewLOB = NULL SET @CurrentIsFileStream = NULL - SET @CurrentIsColumnStore = NULL + SET @CurrentHasColumnstore = NULL SET @CurrentIsComputed = NULL + SET @CurrentIsClusteredIndexComputed = NULL SET @CurrentIsTimestamp = NULL SET @CurrentAllowPageLocks = NULL + SET @CurrentHasFilter = NULL SET @CurrentNoRecompute = NULL SET @CurrentIsIncremental = NULL SET @CurrentRowCount = NULL @@ -2412,5 +2498,11 @@ BEGIN END +GO + + ---------------------------------------------------------------------------------------------------- + +END + GO diff --git a/MaintenanceSolution.sql b/MaintenanceSolution.sql index f68c1613..f2575580 100644 --- a/MaintenanceSolution.sql +++ b/MaintenanceSolution.sql @@ -10,13 +10,21 @@ License: https://ola.hallengren.com/license.html GitHub: https://github.com/olahallengren/sql-server-maintenance-solution -Version: 2024-12-27 18:10:28 +Version: 2025-02-19 21:12:35 You can contact me by e-mail at ola@hallengren.com. Ola Hallengren https://ola.hallengren.com +-- Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. +-- Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Modified to add support for Amazon RDS for SQL Server + +https://github.com/amazon-contributing/aws-sql-server-maintenance-solution +Version: 2025-03-07 09:14 + */ USE [master] -- Specify the database in which the objects will be created. @@ -30,17 +38,24 @@ DECLARE @CleanupTime int = NULL -- Time in hours, after DECLARE @OutputFileDirectory nvarchar(max) = NULL -- Specify the output file directory. If no directory is specified, then the SQL Server error log directory is used. DECLARE @LogToTable nvarchar(max) = 'Y' -- Log commands to a table. + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- +DECLARE @S3BucketArn nvarchar(max) = NULL -- AWS S3 Bucket ARN value. +DECLARE @kms_master_key_arn nvarchar(max) = NULL -- AWS kms master key ARN value. + ---------------------------------------------------------------------------------------------------- + DECLARE @ErrorMessage nvarchar(max) -IF IS_SRVROLEMEMBER('sysadmin') = 0 AND NOT (DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa') +IF IS_SRVROLEMEMBER('sysadmin') = 0 AND NOT (EXISTS (SELECT * FROM sys.databases WHERE [name] = 'rdsadmin') AND SUSER_SNAME(0x01) = 'rdsa') BEGIN SET @ErrorMessage = 'You need to be a member of the SysAdmin server role to install the SQL Server Maintenance Solution.' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END -IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE database_id = DB_ID()) >= 90 +IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE [name] = DB_NAME()) >= 90 BEGIN - SET @ErrorMessage = 'The database ' + QUOTENAME(DB_NAME(DB_ID())) + ' has to be in compatibility level 90 or higher.' + SET @ErrorMessage = 'The database ' + QUOTENAME(DB_NAME()) + ' has to be in compatibility level 90 or higher.' RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END @@ -56,6 +71,16 @@ BEGIN RAISERROR(@ErrorMessage,16,1) WITH NOWAIT END + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- +IF ( DB_NAME() IN('master','rdsadmin') ) AND (DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa') +BEGIN + SET @ErrorMessage = 'SQL Server Maintenance Solution cannot be installed in master or rdsadmin database' + RAISERROR(@ErrorMessage,16,1) WITH NOWAIT +END + ---------------------------------------------------------------------------------------------------- + IF OBJECT_ID('tempdb..#Config') IS NOT NULL DROP TABLE #Config CREATE TABLE #Config ([Name] nvarchar(max), @@ -67,7 +92,13 @@ INSERT INTO #Config ([Name], [Value]) VALUES('BackupURL', @BackupURL) INSERT INTO #Config ([Name], [Value]) VALUES('CleanupTime', @CleanupTime) INSERT INTO #Config ([Name], [Value]) VALUES('OutputFileDirectory', @OutputFileDirectory) INSERT INTO #Config ([Name], [Value]) VALUES('LogToTable', @LogToTable) -INSERT INTO #Config ([Name], [Value]) VALUES('DatabaseName', DB_NAME(DB_ID())) +INSERT INTO #Config ([Name], [Value]) VALUES('DatabaseName', DB_NAME()) + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- +INSERT INTO #Config ([Name], [Value]) VALUES('S3BucketArn', @S3BucketArn) +INSERT INTO #Config ([Name], [Value]) VALUES('kms_master_key_arn', @kms_master_key_arn) + ---------------------------------------------------------------------------------------------------- GO SET ANSI_NULLS ON GO @@ -98,6 +129,80 @@ CREATE TABLE [dbo].[CommandLog]( )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ) END +GO + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[RDS_BackupLog]') AND type in (N'U')) AND EXISTS(SELECT DB_ID('rdsadmin')) AND SUSER_SNAME(0x01) = 'rdsa' +BEGIN + CREATE TABLE [dbo].[RDS_BackupLog]( + [ID] [int] NOT NULL, + [task_id] [int] NOT NULL, + [Status] [nvarchar](max) NULL, + [task_Info] [nvarchar](max) NULL, + CONSTRAINT [PK_RDS_BackupLog] PRIMARY KEY CLUSTERED + ( [ID] ASC, [task_id] ASC ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ) +END +GO + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Queue]') AND type in (N'U')) +BEGIN +CREATE TABLE [dbo].[Queue]( + [QueueID] [int] IDENTITY(1,1) NOT NULL, + [SchemaName] [sysname] NOT NULL, + [ObjectName] [sysname] NOT NULL, + [Parameters] [nvarchar](max) NOT NULL, + [QueueStartTime] [datetime2](7) NULL, + [SessionID] [smallint] NULL, + [RequestID] [int] NULL, + [RequestStartTime] [datetime] NULL, + CONSTRAINT [PK_Queue] PRIMARY KEY CLUSTERED +( + [QueueID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) +END +GO + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[QueueDatabase]') AND type in (N'U')) +BEGIN +CREATE TABLE [dbo].[QueueDatabase]( + [QueueID] [int] NOT NULL, + [DatabaseName] [sysname] NOT NULL, + [DatabaseOrder] [int] NULL, + [DatabaseStartTime] [datetime2](7) NULL, + [DatabaseEndTime] [datetime2](7) NULL, + [SessionID] [smallint] NULL, + [RequestID] [int] NULL, + [RequestStartTime] [datetime] NULL, + CONSTRAINT [PK_QueueDatabase] PRIMARY KEY CLUSTERED +( + [QueueID] ASC, + [DatabaseName] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) +END +GO +IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_QueueDatabase_Queue]') AND parent_object_id = OBJECT_ID(N'[dbo].[QueueDatabase]')) +ALTER TABLE [dbo].[QueueDatabase] WITH CHECK ADD CONSTRAINT [FK_QueueDatabase_Queue] FOREIGN KEY([QueueID]) +REFERENCES [dbo].[Queue] ([QueueID]) +GO +IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_QueueDatabase_Queue]') AND parent_object_id = OBJECT_ID(N'[dbo].[QueueDatabase]')) +ALTER TABLE [dbo].[QueueDatabase] CHECK CONSTRAINT [FK_QueueDatabase_Queue] +GO + ---------------------------------------------------------------------------------------------------- GO SET ANSI_NULLS ON GO @@ -137,7 +242,10 @@ BEGIN --// Source: https://ola.hallengren.com //-- --// License: https://ola.hallengren.com/license.html //-- --// GitHub: https://github.com/olahallengren/sql-server-maintenance-solution //-- - --// Version: 2024-12-27 18:10:28 //-- + --// Version: 2025-02-19 21:12:35 //-- + --// //-- + --// Forked Changes https://github.com/amazon-contributing/aws-sql-server-maintenance-solution //-- + --// Version: 2024-12-30 12:58 //-- ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON @@ -171,14 +279,36 @@ BEGIN DECLARE @RevertCommand nvarchar(max) + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + DECLARE @AmazonRDS bit = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END + DECLARE @task_id INT + + DECLARE @RDSQueue TABLE ([task_id] INT, + [task_type] nvarchar(max), + [database_name] nvarchar(max), + [% complete] nvarchar(max), + [duration (mins)] nvarchar(max), + [lifecycle] nvarchar(max), + [task_info] nvarchar(max), + [last_updated] nvarchar(max), + [created_at] nvarchar(max), + [S3_object_arn] nvarchar(max), + [overwrite_s3_backup_file] nvarchar(max), + [KMS_master_key_arn] nvarchar(max), + [filepath] nvarchar(max), + [overwrite_file] BIT) + ---------------------------------------------------------------------------------------------------- + ---------------------------------------------------------------------------------------------------- --// Check core requirements //-- ---------------------------------------------------------------------------------------------------- - IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE database_id = DB_ID()) >= 90 + IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE [name] = DB_NAME()) >= 90 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The database ' + QUOTENAME(DB_NAME(DB_ID())) + ' has to be in compatibility level 90 or higher.', 16, 1 + SELECT 'The database ' + QUOTENAME(DB_NAME()) + ' has to be in compatibility level 90 or higher.', 16, 1 END IF NOT (SELECT uses_ansi_nulls FROM sys.sql_modules WHERE [object_id] = @@PROCID) = 1 @@ -325,9 +455,41 @@ BEGIN IF @Mode = 1 AND @Execute = 'Y' BEGIN - EXECUTE @sp_executesql @stmt = @Command - SET @Error = @@ERROR - SET @ReturnCode = @Error + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @AmazonRDS = 1 + BEGIN + BEGIN TRY + EXECUTE @sp_executesql @stmt = @Command + INSERT INTO @RDSQueue exec msdb..rds_task_status @db_name=@DatabaseName; + SELECT TOP 1 @task_id=task_id from @RDSQueue ORDER BY task_id DESC + INSERT INTO dbo.RDS_BackupLog (ID, task_id, [Status]) VALUES (@ID, @task_id, 'CREATED') + END TRY + BEGIN CATCH + SET @Error = ERROR_NUMBER() + SET @ErrorMessageOriginal = ERROR_MESSAGE() + BEGIN + SET @ErrorMessage = 'RDS:Msg ' + CAST(ERROR_NUMBER() AS nvarchar) + ', ' + ISNULL(ERROR_MESSAGE(),'') + + SET @Severity = CASE WHEN ERROR_NUMBER() IN(1205,1222) THEN @LockMessageSeverity ELSE 16 END + IF @ErrorMessageOriginal NOT LIKE 'A task has already been issued for database: %' + RAISERROR('%s',@Severity,1,@ErrorMessage) WITH LOG + ELSE + BEGIN + SET @ErrorMessage = 'RDS:Msg ' + CAST(ERROR_NUMBER() AS nvarchar) + ', ' + ISNULL(ERROR_MESSAGE(),'') + RAISERROR('%s',@Severity,1,@ErrorMessage) WITH NOWAIT + END + END + END CATCH + END + ELSE + BEGIN + EXECUTE @sp_executesql @stmt = @Command + SET @Error = @@ERROR + SET @ReturnCode = @Error + END + ---------------------------------------------------------------------------------------------------- END IF @Mode = 2 AND @Execute = 'Y' @@ -413,7 +575,7 @@ ALTER PROCEDURE [dbo].[DatabaseBackup] @CopyOnly nvarchar(max) = 'N', @ChangeBackupType nvarchar(max) = 'N', @BackupSoftware nvarchar(max) = NULL, -@CheckSum nvarchar(max) = 'N', +@Checksum nvarchar(max) = 'N', @BlockSize int = NULL, @BufferCount int = NULL, @MaxTransferSize int = NULL, @@ -422,6 +584,7 @@ ALTER PROCEDURE [dbo].[DatabaseBackup] @MaxFileSize int = NULL, @CompressionLevel int = NULL, @Description nvarchar(max) = NULL, +@BackupSetName nvarchar(max) = NULL, @Threads int = NULL, @Throttle int = NULL, @Encrypt nvarchar(max) = 'N', @@ -442,6 +605,7 @@ ALTER PROCEDURE [dbo].[DatabaseBackup] @Updateability nvarchar(max) = 'ALL', @AdaptiveCompression nvarchar(max) = NULL, @ModificationLevel int = NULL, +@MinDatabaseSizeForDifferentialBackup int = NULL, @LogSizeSinceLastLogBackup int = NULL, @TimeSinceLastLogBackup int = NULL, @DataDomainBoostHost nvarchar(max) = NULL, @@ -464,9 +628,20 @@ ALTER PROCEDURE [dbo].[DatabaseBackup] @ExcludeLogShippedFromLogBackup nvarchar(max) = 'Y', @DirectoryCheck nvarchar(max) = 'Y', @BackupOptions nvarchar(max) = NULL, +@Stats int = NULL, +@ExpireDate datetime = NULL, +@RetainDays int = NULL, @StringDelimiter nvarchar(max) = ',', @DatabaseOrder nvarchar(max) = NULL, @DatabasesInParallel nvarchar(max) = 'N', + + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- +@S3BucketArn nvarchar(255) = NULL, +@kms_master_key_arn nvarchar(max) = NULL, + ---------------------------------------------------------------------------------------------------- + @LogToTable nvarchar(max) = 'N', @Execute nvarchar(max) = 'Y' @@ -478,7 +653,9 @@ BEGIN --// Source: https://ola.hallengren.com //-- --// License: https://ola.hallengren.com/license.html //-- --// GitHub: https://github.com/olahallengren/sql-server-maintenance-solution //-- - --// Version: 2024-12-27 18:10:28 //-- + --// Version: 2025-02-19 21:12:35 //-- + --// //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON @@ -531,6 +708,7 @@ BEGIN DECLARE @CurrentDifferentialBaseLSN numeric(25,0) DECLARE @CurrentDifferentialBaseIsSnapshot bit DECLARE @CurrentLogLSN numeric(25,0) + DECLARE @BackupInProcess bit DECLARE @CurrentLatestBackup datetime2 DECLARE @CurrentDatabaseNameFS nvarchar(max) DECLARE @CurrentDirectoryStructure nvarchar(max) @@ -538,7 +716,7 @@ BEGIN DECLARE @CurrentMaxFilePathLength nvarchar(max) DECLARE @CurrentFileName nvarchar(max) DECLARE @CurrentDirectoryID int - DECLARE @CurrentDirectoryPath nvarchar(max) + DECLARE @CurrentDirectoryPath nvarchar(4000) DECLARE @CurrentFilePath nvarchar(max) DECLARE @CurrentDate datetime2 DECLARE @CurrentDateUTC datetime2 @@ -654,6 +832,15 @@ BEGIN DECLARE @Version numeric(18,10) = CAST(LEFT(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)),CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max))) - 1) + '.' + REPLACE(RIGHT(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)), LEN(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max))) - CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)))),'.','') AS numeric(18,10)) + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + DECLARE @CurrentRDSBackupType nvarchar(20) + DECLARE @CurrentRDSDatabaseFileName nvarchar(4000) + + DECLARE @ServerName nvarchar(max) = CASE WHEN SERVERPROPERTY('EngineEdition') = 8 THEN LEFT(CAST(SERVERPROPERTY('ServerName') AS nvarchar(max)),CHARINDEX('.',CAST(SERVERPROPERTY('ServerName') AS nvarchar(max))) - 1) ELSE CAST(SERVERPROPERTY('MachineName') AS nvarchar(max)) END + ---------------------------------------------------------------------------------------------------- + IF @Version >= 14 BEGIN SELECT @HostPlatform = host_platform @@ -664,7 +851,7 @@ BEGIN SET @HostPlatform = 'Windows' END - DECLARE @AmazonRDS bit = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END + DECLARE @AmazonRDS bit = CASE WHEN EXISTS (SELECT * FROM sys.databases WHERE [name] = 'rdsadmin') AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END ---------------------------------------------------------------------------------------------------- --// Log initial information //-- @@ -681,7 +868,7 @@ BEGIN SET @Parameters += ', @CopyOnly = ' + ISNULL('''' + REPLACE(@CopyOnly,'''','''''') + '''','NULL') SET @Parameters += ', @ChangeBackupType = ' + ISNULL('''' + REPLACE(@ChangeBackupType,'''','''''') + '''','NULL') SET @Parameters += ', @BackupSoftware = ' + ISNULL('''' + REPLACE(@BackupSoftware,'''','''''') + '''','NULL') - SET @Parameters += ', @CheckSum = ' + ISNULL('''' + REPLACE(@CheckSum,'''','''''') + '''','NULL') + SET @Parameters += ', @Checksum = ' + ISNULL('''' + REPLACE(@Checksum,'''','''''') + '''','NULL') SET @Parameters += ', @BlockSize = ' + ISNULL(CAST(@BlockSize AS nvarchar),'NULL') SET @Parameters += ', @BufferCount = ' + ISNULL(CAST(@BufferCount AS nvarchar),'NULL') SET @Parameters += ', @MaxTransferSize = ' + ISNULL(CAST(@MaxTransferSize AS nvarchar),'NULL') @@ -690,6 +877,7 @@ BEGIN SET @Parameters += ', @MaxFileSize = ' + ISNULL(CAST(@MaxFileSize AS nvarchar),'NULL') SET @Parameters += ', @CompressionLevel = ' + ISNULL(CAST(@CompressionLevel AS nvarchar),'NULL') SET @Parameters += ', @Description = ' + ISNULL('''' + REPLACE(@Description,'''','''''') + '''','NULL') + SET @Parameters += ', @BackupSetName = ' + ISNULL('''' + REPLACE(@BackupSetName,'''','''''') + '''','NULL') SET @Parameters += ', @Threads = ' + ISNULL(CAST(@Threads AS nvarchar),'NULL') SET @Parameters += ', @Throttle = ' + ISNULL(CAST(@Throttle AS nvarchar),'NULL') SET @Parameters += ', @Encrypt = ' + ISNULL('''' + REPLACE(@Encrypt,'''','''''') + '''','NULL') @@ -710,6 +898,7 @@ BEGIN SET @Parameters += ', @Updateability = ' + ISNULL('''' + REPLACE(@Updateability,'''','''''') + '''','NULL') SET @Parameters += ', @AdaptiveCompression = ' + ISNULL('''' + REPLACE(@AdaptiveCompression,'''','''''') + '''','NULL') SET @Parameters += ', @ModificationLevel = ' + ISNULL(CAST(@ModificationLevel AS nvarchar),'NULL') + SET @Parameters += ', @MinDatabaseSizeForDifferentialBackup = ' + ISNULL('''' + REPLACE(@MinDatabaseSizeForDifferentialBackup,'''','''''') + '''','NULL') SET @Parameters += ', @LogSizeSinceLastLogBackup = ' + ISNULL(CAST(@LogSizeSinceLastLogBackup AS nvarchar),'NULL') SET @Parameters += ', @TimeSinceLastLogBackup = ' + ISNULL(CAST(@TimeSinceLastLogBackup AS nvarchar),'NULL') SET @Parameters += ', @DataDomainBoostHost = ' + ISNULL('''' + REPLACE(@DataDomainBoostHost,'''','''''') + '''','NULL') @@ -731,12 +920,23 @@ BEGIN SET @Parameters += ', @ObjectLevelRecoveryMap = ' + ISNULL('''' + REPLACE(@ObjectLevelRecoveryMap,'''','''''') + '''','NULL') SET @Parameters += ', @ExcludeLogShippedFromLogBackup = ' + ISNULL('''' + REPLACE(@ExcludeLogShippedFromLogBackup,'''','''''') + '''','NULL') SET @Parameters += ', @DirectoryCheck = ' + ISNULL('''' + REPLACE(@DirectoryCheck,'''','''''') + '''','NULL') + SET @Parameters += ', @BackupOptions = ' + ISNULL('''' + REPLACE(@BackupOptions,'''','''''') + '''','NULL') + SET @Parameters += ', @Stats = ' + ISNULL(CAST(@Stats AS nvarchar),'NULL') + SET @Parameters += ', @ExpireDate = ' + ISNULL('''' + CONVERT(nvarchar, @ExpireDate, 21) + '''','NULL') + SET @Parameters += ', @RetainDays = ' + ISNULL(CAST(@RetainDays AS nvarchar),'NULL') SET @Parameters += ', @StringDelimiter = ' + ISNULL('''' + REPLACE(@StringDelimiter,'''','''''') + '''','NULL') SET @Parameters += ', @DatabaseOrder = ' + ISNULL('''' + REPLACE(@DatabaseOrder,'''','''''') + '''','NULL') SET @Parameters += ', @DatabasesInParallel = ' + ISNULL('''' + REPLACE(@DatabasesInParallel,'''','''''') + '''','NULL') SET @Parameters += ', @LogToTable = ' + ISNULL('''' + REPLACE(@LogToTable,'''','''''') + '''','NULL') SET @Parameters += ', @Execute = ' + ISNULL('''' + REPLACE(@Execute,'''','''''') + '''','NULL') + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + SET @Parameters += ', @S3BucketArn = ' + ISNULL('''' + REPLACE(@S3BucketArn,'''','''''') + '''','NULL') + SET @Parameters += ', @kms_master_key_arn = ' + ISNULL('''' + REPLACE(@kms_master_key_arn,'''','''''') + '''','NULL') + ---------------------------------------------------------------------------------------------------- + SET @StartMessage = 'Date and time: ' + CONVERT(nvarchar,@StartTime,120) RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT @@ -752,7 +952,7 @@ BEGIN SET @StartMessage = 'Platform: ' + @HostPlatform RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT - SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME(DB_ID())) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) + SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME()) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT SET @StartMessage = 'Parameters: ' + @Parameters @@ -770,10 +970,10 @@ BEGIN --// Check core requirements //-- ---------------------------------------------------------------------------------------------------- - IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE database_id = DB_ID()) >= 90 + IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE [name] = DB_NAME()) >= 90 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The database ' + QUOTENAME(DB_NAME(DB_ID())) + ' has to be in compatibility level 90 or higher.', 16, 1 + SELECT 'The database ' + QUOTENAME(DB_NAME()) + ' has to be in compatibility level 90 or higher.', 16, 1 END IF NOT (SELECT uses_ansi_nulls FROM sys.sql_modules WHERE [object_id] = @@PROCID) = 1 @@ -824,11 +1024,36 @@ BEGIN SELECT 'The transaction count is not 0.', 16, 1 END - IF @AmazonRDS = 1 + --IF @AmazonRDS = 1 AND (@S3BucketArn = NULL OR @S3BucketArn = '') + --BEGIN + -- INSERT INTO @Errors ([Message], Severity, [State]) + -- SELECT 'The parameter @S3BucketArn is a required for Amazon RDS backups.', 16, 1 + --END + + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF (@AmazonRDS = 1) BEGIN - INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The stored procedure DatabaseBackup is not supported on Amazon RDS.', 16, 1 + IF (@AmazonRDS = 1 AND @S3BucketArn IS NULL) OR (@AmazonRDS = 1 AND @S3BucketArn = '') + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The parameter @S3BucketArn is a required for Amazon RDS backups.', 16, 1 + END + + IF (@S3BucketArn NOT LIKE 'arn:aws:s3:%' AND @S3BucketArn != '') + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The parameter @S3BucketArn is invalid.', 16, 1 + END + + IF (@kms_master_key_arn NOT LIKE 'arn:aws:kms:%' AND @kms_master_key_arn != '') + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The parameter @kms_master_key_arn is invalid.', 16, 1 + END END + ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- --// Select databases //-- @@ -1084,8 +1309,8 @@ BEGIN SET @ErrorMessage = '' SELECT @ErrorMessage = @ErrorMessage + QUOTENAME(DatabaseName) + ', ' FROM @tmpDatabases - WHERE UPPER(DatabaseNameFS) IN(SELECT UPPER(DatabaseNameFS) FROM @tmpDatabases GROUP BY UPPER(DatabaseNameFS) HAVING COUNT(*) > 1) - AND UPPER(DatabaseNameFS) IN(SELECT UPPER(DatabaseNameFS) FROM @tmpDatabases WHERE Selected = 1) + WHERE UPPER(DatabaseNameFS) IN(SELECT UPPER(DatabaseNameFS) FROM @tmpDatabases GROUP BY UPPER(DatabaseNameFS) HAVING COUNT(*) > 1 AND MAX(CAST(Selected AS int)) = 1) + AND DATALENGTH(DatabaseNameFS) > 0 ORDER BY DatabaseName ASC OPTION (RECOMPILE) @@ -1279,14 +1504,21 @@ BEGIN BREAK END - INSERT INTO @DirectoryInfo (FileExists, FileIsADirectory, ParentDirectoryExists) - EXECUTE [master].dbo.xp_fileexist @CurrentRootDirectoryPath + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @AmazonRDS = 0 + BEGIN + INSERT INTO @DirectoryInfo (FileExists, FileIsADirectory, ParentDirectoryExists) + EXECUTE [master].dbo.xp_fileexist @CurrentRootDirectoryPath - IF NOT EXISTS (SELECT * FROM @DirectoryInfo WHERE FileExists = 0 AND FileIsADirectory = 1 AND ParentDirectoryExists = 1) - BEGIN - INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The directory ' + @CurrentRootDirectoryPath + ' does not exist.', 16, 1 + IF NOT EXISTS (SELECT * FROM @DirectoryInfo WHERE FileExists = 0 AND FileIsADirectory = 1 AND ParentDirectoryExists = 1) + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The directory ' + @CurrentRootDirectoryPath + ' does not exist.', 16, 1 + END END + ---------------------------------------------------------------------------------------------------- UPDATE @Directories SET Completed = 1 @@ -1530,7 +1762,11 @@ BEGIN IF @CleanupTime IS NOT NULL AND @URL IS NOT NULL BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The value for the parameter @CleanupTime is not supported. Cleanup is not supported on Azure Blob Storage.', 16, 2 + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + SELECT 'The value for the parameter @CleanupTime is not supported. Cleanup is not supported on Amazon S3 or Azure Blob Storage.', 16, 2 + ---------------------------------------------------------------------------------------------------- END IF @CleanupTime IS NOT NULL AND EXISTS(SELECT * FROM @Directories WHERE DirectoryPath = 'NUL') @@ -1545,10 +1781,10 @@ BEGIN SELECT 'The value for the parameter @CleanupTime is not supported. Cleanup is not supported if the token {DatabaseName} is not part of the directory.', 16, 5 END - IF @CleanupTime IS NOT NULL AND ((@DirectoryStructure NOT LIKE '%{BackupType}%' OR @DirectoryStructure IS NULL) OR (SERVERPROPERTY('IsHadrEnabled') = 1 AND (@AvailabilityGroupDirectoryStructure NOT LIKE '%{BackupType}%' OR @AvailabilityGroupDirectoryStructure IS NULL))) + IF @CleanupTime IS NOT NULL AND ((@DirectoryStructure NOT LIKE '%{BackupType}%' OR @DirectoryStructure IS NULL) OR (SERVERPROPERTY('IsHadrEnabled') = 1 AND (@AvailabilityGroupDirectoryStructure NOT LIKE '%{BackupType}%' OR @AvailabilityGroupDirectoryStructure IS NULL))) AND (SELECT COUNT(*) FROM (SELECT @FileExtensionFull AS FileExtension UNION SELECT @FileExtensionDiff UNION SELECT @FileExtensionLog) FileExtension) <> 3 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The value for the parameter @CleanupTime is not supported. Cleanup is not supported if the token {BackupType} is not part of the directory.', 16, 6 + SELECT 'The value for the parameter @CleanupTime is not supported. Cleanup is not supported if the token {BackupType} is not part of the directory and the file extensions are not unique.', 16, 6 END IF @CleanupTime IS NOT NULL AND @CopyOnly = 'Y' AND ((@DirectoryStructure NOT LIKE '%{CopyOnly}%' OR @DirectoryStructure IS NULL) OR (SERVERPROPERTY('IsHadrEnabled') = 1 AND (@AvailabilityGroupDirectoryStructure NOT LIKE '%{CopyOnly}%' OR @AvailabilityGroupDirectoryStructure IS NULL))) @@ -1673,10 +1909,10 @@ BEGIN ---------------------------------------------------------------------------------------------------- - IF @CheckSum NOT IN ('Y','N') OR @CheckSum IS NULL + IF @Checksum NOT IN ('Y','N') OR @Checksum IS NULL BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The value for the parameter @CheckSum is not supported.', 16, 1 + SELECT 'The value for the parameter @Checksum is not supported.', 16, 1 END ---------------------------------------------------------------------------------------------------- @@ -1825,6 +2061,16 @@ BEGIN SELECT 'The value for the parameter @NumberOfFiles is not supported. The maximum number of files when performing mirrored backups to S3 storage is 32.', 16, 10 END + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @NumberOfFiles > 10 AND @AmazonRDS = 1 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @NumberOfFiles is not supported. The maximum number of files when performing Amazon RDS backups is 10.', 16, 10 + END + ---------------------------------------------------------------------------------------------------- + ---------------------------------------------------------------------------------------------------- IF @MinBackupSizeForMultipleFiles <= 0 @@ -1931,6 +2177,13 @@ BEGIN ---------------------------------------------------------------------------------------------------- + IF LEN(@BackupSetName) > 128 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @BackupSetName is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- IF @Threads IS NOT NULL AND (@BackupSoftware NOT IN('LITESPEED','SQLBACKUP','SQLSAFE') OR @BackupSoftware IS NULL) BEGIN INSERT INTO @Errors ([Message], Severity, [State]) @@ -2278,16 +2531,35 @@ BEGIN SELECT 'The value for the parameter @ModificationLevel is not supported.', 16, 1 END + IF @ModificationLevel <= 0 OR @ModificationLevel > 100 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @ModificationLevel is not supported.', 16, 2 + END IF @ModificationLevel IS NOT NULL AND @ChangeBackupType = 'N' BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The parameter @ModificationLevel can only be used together with @ChangeBackupType = ''Y''.', 16, 2 + SELECT 'The parameter @ModificationLevel can only be used together with @ChangeBackupType = ''Y''.', 16, 3 END IF @ModificationLevel IS NOT NULL AND @BackupType <> 'DIFF' BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The parameter @ModificationLevel can only be used for differential backups.', 16, 3 + SELECT 'The parameter @ModificationLevel can only be used for differential backups.', 16, 4 + END + + ---------------------------------------------------------------------------------------------------- + + IF @MinDatabaseSizeForDifferentialBackup <= 0 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @MinDatabaseSizeForDifferentialBackup is not supported.', 16, 1 + END + + IF @MinDatabaseSizeForDifferentialBackup IS NOT NULL AND @BackupType <> 'DIFF' + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The parameter @MinDatabaseSizeForDifferentialBackup can only be used for differential backups.', 16, 2 END ---------------------------------------------------------------------------------------------------- @@ -2492,7 +2764,7 @@ BEGIN ---------------------------------------------------------------------------------------------------- - IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@DirectoryStructure,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{MajorVersion}',''),'{MinorVersion}','') AS DirectoryStructure) Temp WHERE DirectoryStructure LIKE '%{%' OR DirectoryStructure LIKE '%}%') + IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@DirectoryStructure,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{BackupSetName}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Weekday}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{MajorVersion}',''),'{MinorVersion}','') AS DirectoryStructure) Temp WHERE DirectoryStructure LIKE '%{%' OR DirectoryStructure LIKE '%}%') BEGIN INSERT INTO @Errors ([Message], Severity, [State]) SELECT 'The parameter @DirectoryStructure contains one or more tokens that are not supported.', 16, 1 @@ -2500,7 +2772,7 @@ BEGIN ---------------------------------------------------------------------------------------------------- - IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@AvailabilityGroupDirectoryStructure,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{MajorVersion}',''),'{MinorVersion}','') AS AvailabilityGroupDirectoryStructure) Temp WHERE AvailabilityGroupDirectoryStructure LIKE '%{%' OR AvailabilityGroupDirectoryStructure LIKE '%}%') + IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@AvailabilityGroupDirectoryStructure,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{BackupSetName}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Weekday}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{MajorVersion}',''),'{MinorVersion}','') AS AvailabilityGroupDirectoryStructure) Temp WHERE AvailabilityGroupDirectoryStructure LIKE '%{%' OR AvailabilityGroupDirectoryStructure LIKE '%}%') BEGIN INSERT INTO @Errors ([Message], Severity, [State]) SELECT 'The parameter @AvailabilityGroupDirectoryStructure contains one or more tokens that are not supported.', 16, 1 @@ -2508,7 +2780,7 @@ BEGIN ---------------------------------------------------------------------------------------------------- - IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@FileName,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{FileNumber}',''),'{NumberOfFiles}',''),'{FileExtension}',''),'{MajorVersion}',''),'{MinorVersion}','') AS [FileName]) Temp WHERE [FileName] LIKE '%{%' OR [FileName] LIKE '%}%') + IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@FileName,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{BackupSetName}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Weekday}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{FileNumber}',''),'{NumberOfFiles}',''),'{FileExtension}',''),'{MajorVersion}',''),'{MinorVersion}','') AS [FileName]) Temp WHERE [FileName] LIKE '%{%' OR [FileName] LIKE '%}%') BEGIN INSERT INTO @Errors ([Message], Severity, [State]) SELECT 'The parameter @FileName contains one or more tokens that are not supported.', 16, 1 @@ -2516,7 +2788,7 @@ BEGIN ---------------------------------------------------------------------------------------------------- - IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@AvailabilityGroupFileName,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{FileNumber}',''),'{NumberOfFiles}',''),'{FileExtension}',''),'{MajorVersion}',''),'{MinorVersion}','') AS AvailabilityGroupFileName) Temp WHERE AvailabilityGroupFileName LIKE '%{%' OR AvailabilityGroupFileName LIKE '%}%') + IF EXISTS (SELECT * FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@AvailabilityGroupFileName,'{DirectorySeparator}',''),'{ServerName}',''),'{InstanceName}',''),'{ServiceName}',''),'{ClusterName}',''),'{AvailabilityGroupName}',''),'{DatabaseName}',''),'{BackupType}',''),'{Partial}',''),'{CopyOnly}',''),'{Description}',''),'{BackupSetName}',''),'{Year}',''),'{Month}',''),'{Day}',''),'{Week}',''),'{Weekday}',''),'{Hour}',''),'{Minute}',''),'{Second}',''),'{Millisecond}',''),'{Microsecond}',''),'{FileNumber}',''),'{NumberOfFiles}',''),'{FileExtension}',''),'{MajorVersion}',''),'{MinorVersion}','') AS AvailabilityGroupFileName) Temp WHERE AvailabilityGroupFileName LIKE '%{%' OR AvailabilityGroupFileName LIKE '%}%') BEGIN INSERT INTO @Errors ([Message], Severity, [State]) SELECT 'The parameter @AvailabilityGroupFileName contains one or more tokens that are not supported.', 16, 1 @@ -2638,6 +2910,43 @@ BEGIN ---------------------------------------------------------------------------------------------------- + IF @BackupOptions IS NOT NULL AND @URL IS NULL + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @BackupOptions is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- + + IF @Stats <= 0 OR @Stats > 100 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @Stats is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- + + IF @ExpireDate IS NOT NULL AND @BackupSoftware <> 'LITESPEED' + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @ExpireDate is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- + + IF @RetainDays < 0 + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @RetainDays is not supported.', 16, 1 + END + + IF @RetainDays IS NOT NULL AND @BackupSoftware <> 'LITESPEED' + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @RetainDays is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- IF @StringDelimiter IS NULL OR LEN(@StringDelimiter) > 1 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) @@ -3114,22 +3423,23 @@ BEGIN AND EXISTS(SELECT * FROM sys.all_columns WHERE object_id = OBJECT_ID('sys.dm_db_file_space_usage') AND name = 'modified_extent_page_count') AND (@CurrentAvailabilityGroupRole = 'PRIMARY' OR @CurrentAvailabilityGroupRole IS NULL) AND (@BackupType IN('DIFF','FULL') OR (@ChangeBackupType = 'Y' AND @CurrentBackupType = 'LOG' AND @CurrentRecoveryModel IN('FULL','BULK_LOGGED') AND @CurrentLogLSN IS NULL AND @CurrentDatabaseName <> 'master')) - AND (@ModificationLevel IS NOT NULL OR @MinBackupSizeForMultipleFiles IS NOT NULL OR @MaxFileSize IS NOT NULL) + AND (@ModificationLevel IS NOT NULL OR @MinBackupSizeForMultipleFiles IS NOT NULL OR @MaxFileSize IS NOT NULL OR @MinDatabaseSizeForDifferentialBackup IS NOT NULL) BEGIN SET @CurrentCommand = 'SELECT @ParamAllocatedExtentPageCount = SUM(allocated_extent_page_count), @ParamModifiedExtentPageCount = SUM(modified_extent_page_count) FROM sys.dm_db_file_space_usage' EXECUTE @CurrentDatabase_sp_executesql @stmt = @CurrentCommand, @params = N'@ParamAllocatedExtentPageCount bigint OUTPUT, @ParamModifiedExtentPageCount bigint OUTPUT', @ParamAllocatedExtentPageCount = @CurrentAllocatedExtentPageCount OUTPUT, @ParamModifiedExtentPageCount = @CurrentModifiedExtentPageCount OUTPUT END + SET @BackupInProcess = CASE WHEN EXISTS(SELECT * FROM sys.dm_exec_requests WHERE database_id = DB_ID(@CurrentDatabaseName) AND command = 'BACKUP DATABASE') THEN 1 ELSE 0 END SET @CurrentBackupType = @BackupType IF @ChangeBackupType = 'Y' BEGIN - IF @CurrentBackupType = 'LOG' AND @CurrentRecoveryModel IN('FULL','BULK_LOGGED') AND @CurrentLogLSN IS NULL AND @CurrentDatabaseName <> 'master' + IF @CurrentBackupType = 'LOG' AND @CurrentRecoveryModel IN('FULL','BULK_LOGGED') AND @CurrentLogLSN IS NULL AND @CurrentDatabaseName <> 'master' AND @BackupInProcess = 0 BEGIN SET @CurrentBackupType = 'DIFF' END - IF @CurrentBackupType = 'DIFF' AND (@CurrentDatabaseName = 'master' OR @CurrentDifferentialBaseLSN IS NULL OR (@CurrentModifiedExtentPageCount * 1. / @CurrentAllocatedExtentPageCount * 100 >= @ModificationLevel)) + IF @CurrentBackupType = 'DIFF' AND (@CurrentDatabaseName = 'master' OR @CurrentDifferentialBaseLSN IS NULL OR (@CurrentModifiedExtentPageCount * 1. / @CurrentAllocatedExtentPageCount * 100 >= @ModificationLevel) OR (COALESCE(CAST(@CurrentAllocatedExtentPageCount AS bigint) * 8192, CAST(@CurrentDatabaseSize AS bigint) * 8192) < CAST(@MinDatabaseSizeForDifferentialBackup AS bigint) * 1024 * 1024)) BEGIN SET @CurrentBackupType = 'FULL' END @@ -3186,18 +3496,32 @@ BEGIN FROM CurrentDatabase SELECT @CurrentDatabaseMirroringRole = UPPER(mirroring_role_desc) - FROM sys.database_mirroring - WHERE database_id = DB_ID(@CurrentDatabaseName) + FROM sys.database_mirroring database_mirroring + INNER JOIN sys.databases databases ON database_mirroring.database_id = databases.database_id + WHERE databases.[name] = @CurrentDatabaseName - IF EXISTS (SELECT * FROM msdb.dbo.log_shipping_primary_databases WHERE primary_database = @CurrentDatabaseName) - BEGIN - SET @CurrentLogShippingRole = 'PRIMARY' - END - ELSE - IF EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondary_databases WHERE secondary_database = @CurrentDatabaseName) + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @AmazonRDS = 0 BEGIN - SET @CurrentLogShippingRole = 'SECONDARY' - END + IF EXISTS (SELECT * FROM msdb.dbo.log_shipping_primary_databases WHERE primary_database = @CurrentDatabaseName) + BEGIN + SET @CurrentLogShippingRole = 'PRIMARY' + END + ELSE + IF EXISTS (SELECT * FROM msdb.dbo.log_shipping_secondary_databases WHERE secondary_database = @CurrentDatabaseName) + BEGIN + SET @CurrentLogShippingRole = 'SECONDARY' + END + END + ---------------------------------------------------------------------------------------------------- + + + + + + IF @CurrentAvailabilityGroup IS NOT NULL BEGIN @@ -3238,6 +3562,11 @@ BEGIN SET @DatabaseMessage = 'Last log backup LSN: ' + ISNULL(CAST(@CurrentLogLSN AS nvarchar),'N/A') RAISERROR('%s',10,1,@DatabaseMessage) WITH NOWAIT + IF @CurrentBackupType = 'LOG' AND @BackupInProcess = 1 + BEGIN + SET @DatabaseMessage = 'Full or differential backup in process: ' + CASE WHEN @BackupInProcess = 1 THEN 'Yes' WHEN @BackupInProcess = 0 THEN 'No' ELSE 'N/A' END + RAISERROR('%s',10,1,@DatabaseMessage) WITH NOWAIT + END IF @CurrentBackupType IN('DIFF','FULL') AND EXISTS(SELECT * FROM sys.all_columns WHERE object_id = OBJECT_ID('sys.dm_db_file_space_usage') AND name = 'modified_extent_page_count') BEGIN SET @DatabaseMessage = 'Allocated extent page count: ' + ISNULL(CAST(@CurrentAllocatedExtentPageCount AS nvarchar) + ' (' + CAST(@CurrentAllocatedExtentPageCount * 1. * 8 / 1024 AS nvarchar) + ' MB)','N/A') @@ -3275,6 +3604,7 @@ BEGIN AND NOT (@CurrentIsReadOnly = 0 AND @Updateability = 'READ_ONLY') AND NOT (@CurrentBackupType = 'LOG' AND @LogSizeSinceLastLogBackup IS NOT NULL AND @TimeSinceLastLogBackup IS NOT NULL AND NOT(@CurrentLogSizeSinceLastLogBackup >= @LogSizeSinceLastLogBackup OR @CurrentLogSizeSinceLastLogBackup IS NULL OR DATEDIFF(SECOND,@CurrentLastLogBackup,SYSDATETIME()) >= @TimeSinceLastLogBackup OR @CurrentLastLogBackup IS NULL)) AND NOT (@CurrentBackupType = 'LOG' AND @Updateability = 'READ_ONLY' AND @BackupSoftware = 'DATA_DOMAIN_BOOST') + AND NOT (@CurrentBackupType = 'DIFF' AND @MinDatabaseSizeForDifferentialBackup IS NOT NULL AND (COALESCE(CAST(@CurrentAllocatedExtentPageCount AS bigint) * 8192, CAST(@CurrentDatabaseSize AS bigint) * 8192) < CAST(@MinDatabaseSizeForDifferentialBackup AS bigint) * 1024 * 1024)) BEGIN IF @CurrentBackupType = 'LOG' AND (@CleanupTime IS NOT NULL OR @MirrorCleanupTime IS NOT NULL) @@ -3314,6 +3644,7 @@ BEGIN IF SERVERPROPERTY('InstanceName') IS NULL SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{InstanceName}','') IF @@SERVICENAME IS NULL SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{ServiceName}','') IF @Description IS NULL SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Description}','') + IF @BackupSetName IS NULL SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{BackupSetName}','') IF @Directory IS NULL AND @MirrorDirectory IS NULL AND @URL IS NULL AND @DefaultDirectory LIKE '%' + '.' + @@SERVICENAME + @DirectorySeparator + 'MSSQL' + @DirectorySeparator + 'Backup' BEGIN @@ -3471,10 +3802,12 @@ BEGIN SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Partial}','PARTIAL') SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{CopyOnly}','COPY_ONLY') SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Description}',LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ISNULL(@Description,''),'\',''),'/',''),':',''),'*',''),'?',''),'"',''),'<',''),'>',''),'|','')))) + SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{BackupSetName}',LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ISNULL(@BackupSetName,''),'\',''),'/',''),':',''),'*',''),'?',''),'"',''),'<',''),'>',''),'|','')))) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Year}',CAST(DATEPART(YEAR,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Month}',RIGHT('0' + CAST(DATEPART(MONTH,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Day}',RIGHT('0' + CAST(DATEPART(DAY,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Week}',RIGHT('0' + CAST(DATEPART(WEEK,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) + SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Weekday}',DATENAME(WEEKDAY,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Hour}',RIGHT('0' + CAST(DATEPART(HOUR,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Minute}',RIGHT('0' + CAST(DATEPART(MINUTE,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDirectoryStructure = REPLACE(@CurrentDirectoryStructure,'{Second}',RIGHT('0' + CAST(DATEPART(SECOND,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) @@ -3521,6 +3854,7 @@ BEGIN IF SERVERPROPERTY('InstanceName') IS NULL SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{InstanceName}','') IF @@SERVICENAME IS NULL SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{ServiceName}','') IF @Description IS NULL SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Description}','') + IF @BackupSetName IS NULL SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{BackupSetName}','') IF @CurrentNumberOfFiles = 1 SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{FileNumber}','') IF @CurrentNumberOfFiles = 1 SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{NumberOfFiles}','') @@ -3632,10 +3966,12 @@ BEGIN SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Partial}','PARTIAL') SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{CopyOnly}','COPY_ONLY') SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Description}',LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ISNULL(@Description,''),'\',''),'/',''),':',''),'*',''),'?',''),'"',''),'<',''),'>',''),'|','')))) + SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{BackupSetName}',LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ISNULL(@BackupSetName,''),'\',''),'/',''),':',''),'*',''),'?',''),'"',''),'<',''),'>',''),'|','')))) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Year}',CAST(DATEPART(YEAR,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Month}',RIGHT('0' + CAST(DATEPART(MONTH,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Day}',RIGHT('0' + CAST(DATEPART(DAY,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Week}',RIGHT('0' + CAST(DATEPART(WEEK,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) + SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Weekday}',DATENAME(WEEKDAY,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Hour}',RIGHT('0' + CAST(DATEPART(HOUR,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Minute}',RIGHT('0' + CAST(DATEPART(MINUTE,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) SET @CurrentDatabaseFileName = REPLACE(@CurrentDatabaseFileName,'{Second}',RIGHT('0' + CAST(DATEPART(SECOND,CASE WHEN @TokenTimezone = 'UTC' THEN @CurrentDateUTC ELSE @CurrentDate END) AS nvarchar),2)) @@ -3798,6 +4134,13 @@ BEGIN -- Create directory IF @HostPlatform = 'Windows' AND (@BackupSoftware <> 'DATA_DOMAIN_BOOST' OR @BackupSoftware IS NULL) + + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + AND (@AmazonRDS = 0) + ---------------------------------------------------------------------------------------------------- + AND NOT EXISTS(SELECT * FROM @CurrentDirectories WHERE DirectoryPath = 'NUL' OR DirectoryPath IN(SELECT DirectoryPath FROM @Directories)) BEGIN WHILE (1 = 1) @@ -3813,21 +4156,37 @@ BEGIN BREAK END - SET @CurrentDatabaseContext = 'master' + IF @DirectoryCheck = 'Y' + BEGIN + INSERT INTO @DirectoryInfo (FileExists, FileIsADirectory, ParentDirectoryExists) + EXECUTE [master].dbo.xp_fileexist @CurrentDirectoryPath + END - SET @CurrentCommandType = 'xp_create_subdir' + IF NOT EXISTS (SELECT * FROM @DirectoryInfo WHERE FileExists = 0 AND FileIsADirectory = 1 AND ParentDirectoryExists = 1) + BEGIN + SET @CurrentDatabaseContext = 'master' - SET @CurrentCommand = 'DECLARE @ReturnCode int EXECUTE @ReturnCode = dbo.xp_create_subdir N''' + REPLACE(@CurrentDirectoryPath,'''','''''') + ''' IF @ReturnCode <> 0 RAISERROR(''Error creating directory.'', 16, 1)' + SET @CurrentCommandType = 'xp_create_subdir' - EXECUTE @CurrentCommandOutput = dbo.CommandExecute @DatabaseContext = @CurrentDatabaseContext, @Command = @CurrentCommand, @CommandType = @CurrentCommandType, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute - SET @Error = @@ERROR - IF @Error <> 0 SET @CurrentCommandOutput = @Error - IF @CurrentCommandOutput <> 0 SET @ReturnCode = @CurrentCommandOutput + SET @CurrentCommand = 'DECLARE @ReturnCode int EXECUTE @ReturnCode = dbo.xp_create_subdir N''' + REPLACE(@CurrentDirectoryPath,'''','''''') + ''' IF @ReturnCode <> 0 RAISERROR(''Error creating directory.'', 16, 1)' - UPDATE @CurrentDirectories - SET CreateCompleted = 1, - CreateOutput = @CurrentCommandOutput - WHERE ID = @CurrentDirectoryID + EXECUTE @CurrentCommandOutput = dbo.CommandExecute @DatabaseContext = @CurrentDatabaseContext, @Command = @CurrentCommand, @CommandType = @CurrentCommandType, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute + SET @Error = @@ERROR + IF @Error <> 0 SET @CurrentCommandOutput = @Error + IF @CurrentCommandOutput <> 0 SET @ReturnCode = @CurrentCommandOutput + + UPDATE @CurrentDirectories + SET CreateCompleted = 1, + CreateOutput = @CurrentCommandOutput + WHERE ID = @CurrentDirectoryID + END + ELSE + BEGIN + UPDATE @CurrentDirectories + SET CreateCompleted = 1, + CreateOutput = 0 + WHERE ID = @CurrentDirectoryID + END SET @CurrentDirectoryID = NULL SET @CurrentDirectoryPath = NULL @@ -3836,6 +4195,8 @@ BEGIN SET @CurrentCommand = NULL SET @CurrentCommandOutput = NULL SET @CurrentCommandType = NULL + + DELETE FROM @DirectoryInfo END END @@ -3951,77 +4312,115 @@ BEGIN -- Perform a backup IF NOT EXISTS (SELECT * FROM @CurrentDirectories WHERE DirectoryPath <> 'NUL' AND DirectoryPath NOT IN(SELECT DirectoryPath FROM @Directories) AND (CreateOutput <> 0 OR CreateOutput IS NULL)) - OR @HostPlatform = 'Linux' + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + OR @HostPlatform = 'Linux' OR @AmazonRDS = 1 BEGIN IF @BackupSoftware IS NULL - BEGIN - SET @CurrentDatabaseContext = 'master' - - SELECT @CurrentCommandType = CASE - WHEN @CurrentBackupType IN('DIFF','FULL') THEN 'BACKUP_DATABASE' - WHEN @CurrentBackupType = 'LOG' THEN 'BACKUP_LOG' - END - SELECT @CurrentCommand = CASE - WHEN @CurrentBackupType IN('DIFF','FULL') THEN 'BACKUP DATABASE ' + QUOTENAME(@CurrentDatabaseName) - WHEN @CurrentBackupType = 'LOG' THEN 'BACKUP LOG ' + QUOTENAME(@CurrentDatabaseName) - END - - IF @ReadWriteFileGroups = 'Y' AND @CurrentDatabaseName <> 'master' SET @CurrentCommand += ' READ_WRITE_FILEGROUPS' - - SET @CurrentCommand += ' TO' - - SELECT @CurrentCommand += ' ' + [Type] + ' = N''' + REPLACE(FilePath,'''','''''') + '''' + CASE WHEN ROW_NUMBER() OVER (ORDER BY FilePath ASC) <> @CurrentNumberOfFiles THEN ',' ELSE '' END - FROM @CurrentFiles - WHERE Mirror = 0 - ORDER BY FilePath ASC - - IF EXISTS(SELECT * FROM @CurrentFiles WHERE Mirror = 1) - BEGIN - SET @CurrentCommand += ' MIRROR TO' - - SELECT @CurrentCommand += ' ' + [Type] + ' = N''' + REPLACE(FilePath,'''','''''') + '''' + CASE WHEN ROW_NUMBER() OVER (ORDER BY FilePath ASC) <> @CurrentNumberOfFiles THEN ',' ELSE '' END - FROM @CurrentFiles - WHERE Mirror = 1 - ORDER BY FilePath ASC - END - - SET @CurrentCommand += ' WITH ' - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' - - IF @Version >= 10 - BEGIN - SET @CurrentCommand += CASE WHEN @Compress = 'Y' AND (@CurrentIsEncrypted = 0 OR (@CurrentIsEncrypted = 1 AND ((@Version >= 13 AND @CurrentMaxTransferSize >= 65537) OR @Version >= 15.0404316 OR SERVERPROPERTY('EngineEdition') = 8))) THEN ', COMPRESSION' ELSE ', NO_COMPRESSION' END - END - - IF @Compress = 'Y' AND @CompressionAlgorithm IS NOT NULL - BEGIN - SET @CurrentCommand += ' (ALGORITHM = ' + @CompressionAlgorithm + ')' - END - - IF @CurrentBackupType = 'DIFF' SET @CurrentCommand += ', DIFFERENTIAL' - - IF EXISTS(SELECT * FROM @CurrentFiles WHERE Mirror = 1) - BEGIN - SET @CurrentCommand += ', FORMAT' - END - - IF @CopyOnly = 'Y' SET @CurrentCommand += ', COPY_ONLY' - IF @NoRecovery = 'Y' AND @CurrentBackupType = 'LOG' SET @CurrentCommand += ', NORECOVERY' - IF @Init = 'Y' SET @CurrentCommand += ', INIT' - IF @Format = 'Y' SET @CurrentCommand += ', FORMAT' - IF @BlockSize IS NOT NULL SET @CurrentCommand += ', BLOCKSIZE = ' + CAST(@BlockSize AS nvarchar) - IF @BufferCount IS NOT NULL SET @CurrentCommand += ', BUFFERCOUNT = ' + CAST(@BufferCount AS nvarchar) - IF @CurrentMaxTransferSize IS NOT NULL SET @CurrentCommand += ', MAXTRANSFERSIZE = ' + CAST(@CurrentMaxTransferSize AS nvarchar) - IF @Description IS NOT NULL SET @CurrentCommand += ', DESCRIPTION = N''' + REPLACE(@Description,'''','''''') + '''' - IF @BackupOptions IS NOT NULL SET @CurrentCommand += ', BACKUP_OPTIONS = N''' + REPLACE(@BackupOptions,'''','''''') + '''' - IF @Encrypt = 'Y' SET @CurrentCommand += ', ENCRYPTION (ALGORITHM = ' + UPPER(@EncryptionAlgorithm) + ', ' - IF @Encrypt = 'Y' AND @ServerCertificate IS NOT NULL SET @CurrentCommand += 'SERVER CERTIFICATE = ' + QUOTENAME(@ServerCertificate) - IF @Encrypt = 'Y' AND @ServerAsymmetricKey IS NOT NULL SET @CurrentCommand += 'SERVER ASYMMETRIC KEY = ' + QUOTENAME(@ServerAsymmetricKey) - IF @Encrypt = 'Y' SET @CurrentCommand += ')' - IF @URL IS NOT NULL AND @Credential IS NOT NULL SET @CurrentCommand += ', CREDENTIAL = N''' + REPLACE(@Credential,'''','''''') + '''' - END + BEGIN + IF @AmazonRDS = 1 + BEGIN + SET @CurrentDatabaseContext = 'master' + + SELECT @CurrentCommandType = CASE + WHEN @CurrentBackupType IN('DIFF','FULL') THEN 'BACKUP_DATABASE' + + END + + SELECT @CurrentRDSBackupType = CASE + WHEN @CurrentBackupType = 'DIFF' THEN 'DIFFERENTIAL' + WHEN @CurrentBackupType = 'FULL' THEN 'FULL' + END + + IF @CurrentNumberOfFiles > 10 SET @CurrentNumberOfFiles = 10 + + SET @CurrentDatabaseFileName = @ServerName + '/' + @CurrentDatabaseFileName + + IF @CurrentNumberOfFiles > 1 + SELECT @CurrentDatabaseFileName=REPLACE(@CurrentDatabaseFileName,'_{FileNumber}','*'); + + IF (@kms_master_key_arn IS NULL) + SET @kms_master_key_arn = '' + + SET @CurrentCommand = 'EXEC msdb.dbo.rds_backup_database @source_db_name = ' + QUOTENAME(@CurrentDatabaseName) + ', @s3_arn_to_backup_to = ' + '''' + @S3BucketArn + '/' + @CurrentDatabaseFileName + '''' + ', @kms_master_key_arn = ' + '''' + @kms_master_key_arn + '''' + ', @overwrite_s3_backup_file=1 ' + ', @type=' + '''' + @CurrentRDSBackupType + '''' + ', @number_of_files= ' + CAST(@CurrentNumberOfFiles AS VarChar(2)) + ';' + END + ELSE + ---------------------------------------------------------------------------------------------------- + BEGIN + SET @CurrentDatabaseContext = 'master' + + SELECT @CurrentCommandType = CASE + WHEN @CurrentBackupType IN('DIFF','FULL') THEN 'BACKUP_DATABASE' + WHEN @CurrentBackupType = 'LOG' THEN 'BACKUP_LOG' + END + + SELECT @CurrentCommand = CASE + WHEN @CurrentBackupType IN('DIFF','FULL') THEN 'BACKUP DATABASE ' + QUOTENAME(@CurrentDatabaseName) + WHEN @CurrentBackupType = 'LOG' THEN 'BACKUP LOG ' + QUOTENAME(@CurrentDatabaseName) + END + + IF @ReadWriteFileGroups = 'Y' AND @CurrentDatabaseName <> 'master' SET @CurrentCommand += ' READ_WRITE_FILEGROUPS' + + SET @CurrentCommand += ' TO' + + SELECT @CurrentCommand += ' ' + [Type] + ' = N''' + REPLACE(FilePath,'''','''''') + '''' + CASE WHEN ROW_NUMBER() OVER (ORDER BY FilePath ASC) <> @CurrentNumberOfFiles THEN ',' ELSE '' END + FROM @CurrentFiles + WHERE Mirror = 0 + ORDER BY FilePath ASC + + IF EXISTS(SELECT * FROM @CurrentFiles WHERE Mirror = 1) + BEGIN + SET @CurrentCommand += ' MIRROR TO' + + SELECT @CurrentCommand += ' ' + [Type] + ' = N''' + REPLACE(FilePath,'''','''''') + '''' + CASE WHEN ROW_NUMBER() OVER (ORDER BY FilePath ASC) <> @CurrentNumberOfFiles THEN ',' ELSE '' END + FROM @CurrentFiles + WHERE Mirror = 1 + ORDER BY FilePath ASC + END + + SET @CurrentCommand += ' WITH ' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + + IF @Version >= 10 + BEGIN + SET @CurrentCommand += CASE WHEN @Compress = 'Y' AND (@CurrentIsEncrypted = 0 OR (@CurrentIsEncrypted = 1 AND ((@Version >= 13 AND @CurrentMaxTransferSize >= 65537) OR @Version >= 15.0404316 OR SERVERPROPERTY('EngineEdition') = 8))) THEN ', COMPRESSION' ELSE ', NO_COMPRESSION' END + END + + IF @Compress = 'Y' AND @CompressionAlgorithm IS NOT NULL + BEGIN + SET @CurrentCommand += ' (ALGORITHM = ' + @CompressionAlgorithm + ')' + END + + IF @CurrentBackupType = 'DIFF' SET @CurrentCommand += ', DIFFERENTIAL' + + IF EXISTS(SELECT * FROM @CurrentFiles WHERE Mirror = 1) + BEGIN + SET @CurrentCommand += ', FORMAT' + END + + IF @CopyOnly = 'Y' SET @CurrentCommand += ', COPY_ONLY' + IF @NoRecovery = 'Y' AND @CurrentBackupType = 'LOG' SET @CurrentCommand += ', NORECOVERY' + IF @Init = 'Y' SET @CurrentCommand += ', INIT' + IF @Format = 'Y' SET @CurrentCommand += ', FORMAT' + IF @BlockSize IS NOT NULL SET @CurrentCommand += ', BLOCKSIZE = ' + CAST(@BlockSize AS nvarchar) + IF @BufferCount IS NOT NULL SET @CurrentCommand += ', BUFFERCOUNT = ' + CAST(@BufferCount AS nvarchar) + IF @CurrentMaxTransferSize IS NOT NULL SET @CurrentCommand += ', MAXTRANSFERSIZE = ' + CAST(@CurrentMaxTransferSize AS nvarchar) + IF @Description IS NOT NULL SET @CurrentCommand += ', DESCRIPTION = N''' + REPLACE(@Description,'''','''''') + '''' + IF @BackupSetName IS NOT NULL SET @CurrentCommand += ', NAME = N''' + REPLACE(@BackupSetName,'''','''''') + '''' + IF @Stats IS NOT NULL SET @CurrentCommand += ', STATS = ' + CAST(@Stats AS nvarchar) + IF @BackupOptions IS NOT NULL SET @CurrentCommand += ', BACKUP_OPTIONS = N''' + REPLACE(@BackupOptions,'''','''''') + '''' + IF @Encrypt = 'Y' SET @CurrentCommand += ', ENCRYPTION (ALGORITHM = ' + UPPER(@EncryptionAlgorithm) + ', ' + IF @Encrypt = 'Y' AND @ServerCertificate IS NOT NULL SET @CurrentCommand += 'SERVER CERTIFICATE = ' + QUOTENAME(@ServerCertificate) + IF @Encrypt = 'Y' AND @ServerAsymmetricKey IS NOT NULL SET @CurrentCommand += 'SERVER ASYMMETRIC KEY = ' + QUOTENAME(@ServerAsymmetricKey) + IF @Encrypt = 'Y' SET @CurrentCommand += ')' + IF @URL IS NOT NULL AND @Credential IS NOT NULL SET @CurrentCommand += ', CREDENTIAL = N''' + REPLACE(@Credential,'''','''''') + '''' + IF @ExpireDate IS NOT NULL SET @CurrentCommand += ', EXPIREDATE = ''' + CONVERT(nvarchar, @ExpireDate, 21) + '''' + IF @RetainDays IS NOT NULL SET @CurrentCommand += ', RETAINDAYS = ' + CAST(@RetainDays AS nvarchar) + END + END IF @BackupSoftware = 'LITESPEED' BEGIN @@ -4051,8 +4450,8 @@ BEGIN END SET @CurrentCommand += ', @with = ''' - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' IF @CurrentBackupType = 'DIFF' SET @CurrentCommand += ', DIFFERENTIAL' IF @CopyOnly = 'Y' SET @CurrentCommand += ', COPY_ONLY' IF @NoRecovery = 'Y' AND @CurrentBackupType = 'LOG' SET @CurrentCommand += ', NORECOVERY' @@ -4069,6 +4468,8 @@ BEGIN IF @Throttle IS NOT NULL SET @CurrentCommand += ', @throttle = ' + CAST(@Throttle AS nvarchar) IF @Description IS NOT NULL SET @CurrentCommand += ', @desc = N''' + REPLACE(@Description,'''','''''') + '''' IF @ObjectLevelRecoveryMap = 'Y' SET @CurrentCommand += ', @olrmap = 1' + IF @ExpireDate IS NOT NULL SET @CurrentCommand += ', @expiration = ''' + CONVERT(nvarchar, @ExpireDate, 21) + '''' + IF @RetainDays IS NOT NULL SET @CurrentCommand += ', @retaindays = ' + CAST(@RetainDays AS nvarchar) IF @EncryptionAlgorithm IS NOT NULL SET @CurrentCommand += ', @cryptlevel = ' + CASE WHEN @EncryptionAlgorithm = 'RC2_40' THEN '0' @@ -4113,8 +4514,8 @@ BEGIN SET @CurrentCommand += ' MIRRORFILE' + ' = N''' + REPLACE((SELECT FilePath FROM @CurrentFiles WHERE Mirror = 1),'''','''''') + ''', ' END - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' IF @CurrentBackupType = 'DIFF' SET @CurrentCommand += ', DIFFERENTIAL' IF @CopyOnly = 'Y' SET @CurrentCommand += ', COPY_ONLY' IF @NoRecovery = 'Y' AND @CurrentBackupType = 'LOG' SET @CurrentCommand += ', NORECOVERY' @@ -4154,7 +4555,7 @@ BEGIN SET @CurrentCommand += ', @backuptype = ' + CASE WHEN @CurrentBackupType = 'FULL' THEN '''Full''' WHEN @CurrentBackupType = 'DIFF' THEN '''Differential''' WHEN @CurrentBackupType = 'LOG' THEN '''Log''' END IF @ReadWriteFileGroups = 'Y' AND @CurrentDatabaseName <> 'master' SET @CurrentCommand += ', @readwritefilegroups = 1' - SET @CurrentCommand += ', @checksum = ' + CASE WHEN @CheckSum = 'Y' THEN '1' WHEN @CheckSum = 'N' THEN '0' END + SET @CurrentCommand += ', @checksum = ' + CASE WHEN @Checksum = 'Y' THEN '1' WHEN @Checksum = 'N' THEN '0' END SET @CurrentCommand += ', @copyonly = ' + CASE WHEN @CopyOnly = 'Y' THEN '1' WHEN @CopyOnly = 'N' THEN '0' END IF @CompressionLevel IS NOT NULL SET @CurrentCommand += ', @compressionlevel = ' + CAST(@CompressionLevel AS nvarchar) IF @Threads IS NOT NULL SET @CurrentCommand += ', @threads = ' + CAST(@Threads AS nvarchar) @@ -4178,7 +4579,7 @@ BEGIN SET @CurrentCommand = 'DECLARE @ReturnCode int EXECUTE @ReturnCode = dbo.emc_run_backup ''' - SET @CurrentCommand += ' -c ' + CASE WHEN @CurrentAvailabilityGroup IS NOT NULL THEN @Cluster ELSE CAST(SERVERPROPERTY('MachineName') AS nvarchar) END + SET @CurrentCommand += ' -c ' + CASE WHEN @Cluster IS NOT NULL AND @CurrentAvailabilityGroup IS NOT NULL THEN @Cluster ELSE CAST(SERVERPROPERTY('MachineName') AS nvarchar) END SET @CurrentCommand += ' -l ' + CASE WHEN @CurrentBackupType = 'FULL' THEN 'full' @@ -4190,7 +4591,7 @@ BEGIN IF @CleanupTime IS NOT NULL SET @CurrentCommand += ' -y +' + CAST(@CleanupTime/24 + CASE WHEN @CleanupTime%24 > 0 THEN 1 ELSE 0 END AS nvarchar) + 'd' - IF @CheckSum = 'Y' SET @CurrentCommand += ' -k' + IF @Checksum = 'Y' SET @CurrentCommand += ' -k' SET @CurrentCommand += ' -S ' + CAST(@CurrentNumberOfFiles AS nvarchar) @@ -4207,9 +4608,11 @@ BEGIN SET @CurrentCommand += ' -a "NSR_SKIP_NON_BACKUPABLE_STATE_DB=TRUE"' SET @CurrentCommand += ' -a "BACKUP_PROMOTION=NONE"' IF @CopyOnly = 'Y' SET @CurrentCommand += ' -a "NSR_COPY_ONLY=TRUE"' + IF @BackupSetName IS NOT NULL SET @CurrentCommand += ' -N "' + REPLACE(@BackupSetName,'''','''''') + '"' - IF SERVERPROPERTY('InstanceName') IS NULL SET @CurrentCommand += ' "MSSQL' + ':' + REPLACE(REPLACE(@CurrentDatabaseName,'''',''''''),'.','\.') + '"' - IF SERVERPROPERTY('InstanceName') IS NOT NULL SET @CurrentCommand += ' "MSSQL$' + CAST(SERVERPROPERTY('InstanceName') AS nvarchar) + ':' + REPLACE(REPLACE(@CurrentDatabaseName,'''',''''''),'.','\.') + '"' + IF SERVERPROPERTY('InstanceName') IS NULL SET @CurrentCommand += ' "MSSQL' + IF SERVERPROPERTY('InstanceName') IS NOT NULL SET @CurrentCommand += ' "MSSQL$' + CAST(SERVERPROPERTY('InstanceName') AS nvarchar) + SET @CurrentCommand += ':' + REPLACE(REPLACE(@CurrentDatabaseName,'''',''''''),'.','\.') + '"' SET @CurrentCommand += '''' @@ -4224,7 +4627,11 @@ BEGIN END -- Verify the backup - IF @CurrentBackupOutput = 0 AND @Verify = 'Y' + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @CurrentBackupOutput = 0 AND @Verify = 'Y' AND @AmazonRDS = 0 + ---------------------------------------------------------------------------------------------------- BEGIN WHILE (1 = 1) BEGIN @@ -4253,8 +4660,9 @@ BEGIN ORDER BY FilePath ASC SET @CurrentCommand += ' WITH ' - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Stats IS NOT NULL SET @CurrentCommand += ', STATS = ' + CAST(@Stats AS nvarchar) IF @BackupOptions IS NOT NULL SET @CurrentCommand += ', RESTORE_OPTIONS = N''' + REPLACE(@BackupOptions,'''','''''') + '''' IF @URL IS NOT NULL AND @Credential IS NOT NULL SET @CurrentCommand += ', CREDENTIAL = N''' + REPLACE(@Credential,'''','''''') + '''' END @@ -4273,8 +4681,8 @@ BEGIN ORDER BY FilePath ASC SET @CurrentCommand += ', @with = ''' - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' SET @CurrentCommand += '''' IF @EncryptionKey IS NOT NULL SET @CurrentCommand += ', @encryptionkey = N''' + REPLACE(@EncryptionKey,'''','''''') + '''' @@ -4295,8 +4703,8 @@ BEGIN ORDER BY FilePath ASC SET @CurrentCommand += ' WITH ' - IF @CheckSum = 'Y' SET @CurrentCommand += 'CHECKSUM' - IF @CheckSum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' + IF @Checksum = 'Y' SET @CurrentCommand += 'CHECKSUM' + IF @Checksum = 'N' SET @CurrentCommand += 'NO_CHECKSUM' IF @EncryptionKey IS NOT NULL SET @CurrentCommand += ', PASSWORD = N''' + REPLACE(@EncryptionKey,'''','''''') + '''' SET @CurrentCommand = 'DECLARE @ReturnCode int EXECUTE @ReturnCode = dbo.sqlbackup N''-SQL "' + REPLACE(@CurrentCommand,'''','''''') + '"''' + ' IF @ReturnCode <> 0 RAISERROR(''Error verifying SQLBackup backup.'', 16, 1)' @@ -4497,6 +4905,7 @@ BEGIN SET @CurrentDifferentialBaseLSN = NULL SET @CurrentDifferentialBaseIsSnapshot = NULL SET @CurrentLogLSN = NULL + SET @BackupInProcess = NULL SET @CurrentLatestBackup = NULL SET @CurrentDatabaseNameFS = NULL SET @CurrentDirectoryStructure = NULL @@ -4569,6 +4978,7 @@ ALTER PROCEDURE [dbo].[DatabaseIntegrityCheck] @DataPurity nvarchar(max) = 'N', @NoIndex nvarchar(max) = 'N', @ExtendedLogicalChecks nvarchar(max) = 'N', +@NoInformationalMessages nvarchar(max) = 'N', @TabLock nvarchar(max) = 'N', @FileGroups nvarchar(max) = NULL, @Objects nvarchar(max) = NULL, @@ -4593,7 +5003,7 @@ BEGIN --// Source: https://ola.hallengren.com //-- --// License: https://ola.hallengren.com/license.html //-- --// GitHub: https://github.com/olahallengren/sql-server-maintenance-solution //-- - --// Version: 2024-12-27 18:10:28 //-- + --// Version: 2025-02-19 21:12:35 //-- ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON @@ -4745,7 +5155,7 @@ BEGIN SET @HostPlatform = 'Windows' END - DECLARE @AmazonRDS bit = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END + DECLARE @AmazonRDS bit = CASE WHEN SERVERPROPERTY('EngineEdition') IN (5, 8) THEN 0 WHEN EXISTS (SELECT * FROM sys.databases WHERE [name] = 'rdsadmin') AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END ---------------------------------------------------------------------------------------------------- --// Log initial information //-- @@ -4757,6 +5167,7 @@ BEGIN SET @Parameters += ', @DataPurity = ' + ISNULL('''' + REPLACE(@DataPurity,'''','''''') + '''','NULL') SET @Parameters += ', @NoIndex = ' + ISNULL('''' + REPLACE(@NoIndex,'''','''''') + '''','NULL') SET @Parameters += ', @ExtendedLogicalChecks = ' + ISNULL('''' + REPLACE(@ExtendedLogicalChecks,'''','''''') + '''','NULL') + SET @Parameters += ', @NoInformationalMessages = ' + ISNULL('''' + REPLACE(@NoInformationalMessages,'''','''''') + '''','NULL') SET @Parameters += ', @TabLock = ' + ISNULL('''' + REPLACE(@TabLock,'''','''''') + '''','NULL') SET @Parameters += ', @FileGroups = ' + ISNULL('''' + REPLACE(@FileGroups,'''','''''') + '''','NULL') SET @Parameters += ', @Objects = ' + ISNULL('''' + REPLACE(@Objects,'''','''''') + '''','NULL') @@ -4788,7 +5199,7 @@ BEGIN SET @StartMessage = 'Platform: ' + @HostPlatform RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT - SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME(DB_ID())) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) + SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME()) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT SET @StartMessage = 'Parameters: ' + @Parameters @@ -4806,10 +5217,10 @@ BEGIN --// Check core requirements //-- ---------------------------------------------------------------------------------------------------- - IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE database_id = DB_ID()) >= 90 + IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE [name] = DB_NAME()) >= 90 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The database ' + QUOTENAME(DB_NAME(DB_ID())) + ' has to be in compatibility level 90 or higher.', 16, 1 + SELECT 'The database ' + QUOTENAME(DB_NAME()) + ' has to be in compatibility level 90 or higher.', 16, 1 END IF NOT (SELECT uses_ansi_nulls FROM sys.sql_modules WHERE [object_id] = @@PROCID) = 1 @@ -5304,6 +5715,13 @@ BEGIN ---------------------------------------------------------------------------------------------------- + IF @NoInformationalMessages NOT IN ('Y','N') OR @NoInformationalMessages IS NULL + BEGIN + INSERT INTO @Errors ([Message], Severity, [State]) + SELECT 'The value for the parameter @NoInformationalMessages is not supported.', 16, 1 + END + + ---------------------------------------------------------------------------------------------------- IF @TabLock NOT IN ('Y','N') OR @TabLock IS NULL BEGIN INSERT INTO @Errors ([Message], Severity, [State]) @@ -5909,8 +6327,8 @@ BEGIN SET @DatabaseMessage = 'Recovery model: ' + @CurrentRecoveryModel RAISERROR('%s',10,1,@DatabaseMessage) WITH NOWAIT END - - IF @Version >= 11 AND SERVERPROPERTY('IsHadrEnabled') = 1 + + IF @Version >= 11 AND SERVERPROPERTY('IsHadrEnabled') = 1 BEGIN SELECT @CurrentReplicaID = databases.replica_id FROM sys.databases databases @@ -5940,11 +6358,12 @@ BEGIN IF SERVERPROPERTY('EngineEdition') <> 5 BEGIN SELECT @CurrentDatabaseMirroringRole = UPPER(mirroring_role_desc) - FROM sys.database_mirroring - WHERE database_id = DB_ID(@CurrentDatabaseName) + FROM sys.database_mirroring database_mirroring + INNER JOIN sys.databases databases ON database_mirroring.database_id = databases.database_id + WHERE databases.[name] = @CurrentDatabaseName END - - IF @CurrentAvailabilityGroup IS NOT NULL + + IF @CurrentAvailabilityGroup IS NOT NULL BEGIN SET @DatabaseMessage = 'Availability group: ' + ISNULL(@CurrentAvailabilityGroup,'N/A') RAISERROR('%s',10,1,@DatabaseMessage) WITH NOWAIT @@ -5982,6 +6401,7 @@ BEGIN AND ((@AvailabilityGroupReplicas = 'PRIMARY' AND @CurrentAvailabilityGroupRole = 'PRIMARY') OR (@AvailabilityGroupReplicas = 'SECONDARY' AND @CurrentAvailabilityGroupRole = 'SECONDARY') OR (@AvailabilityGroupReplicas = 'PREFERRED_BACKUP_REPLICA' AND @CurrentIsPreferredBackupReplica = 1) OR @AvailabilityGroupReplicas = 'ALL' OR @CurrentAvailabilityGroupRole IS NULL) AND NOT (@CurrentIsReadOnly = 1 AND @Updateability = 'READ_WRITE') AND NOT (@CurrentIsReadOnly = 0 AND @Updateability = 'READ_ONLY') + AND NOT (@AmazonRDS = 1 AND @CurrentDatabaseName = 'rdsadmin') BEGIN -- Check database @@ -5995,10 +6415,11 @@ BEGIN IF @LockTimeout IS NOT NULL SET @CurrentCommand = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand += 'DBCC CHECKDB (' + QUOTENAME(@CurrentDatabaseName) IF @NoIndex = 'Y' SET @CurrentCommand += ', NOINDEX' - SET @CurrentCommand += ') WITH NO_INFOMSGS, ALL_ERRORMSGS' + SET @CurrentCommand += ') WITH ALL_ERRORMSGS' IF @DataPurity = 'Y' SET @CurrentCommand += ', DATA_PURITY' IF @PhysicalOnly = 'Y' SET @CurrentCommand += ', PHYSICAL_ONLY' IF @ExtendedLogicalChecks = 'Y' SET @CurrentCommand += ', EXTENDED_LOGICAL_CHECKS' + IF @NoInformationalMessages = 'Y' SET @CurrentCommand += ', NO_INFOMSGS' IF @TabLock = 'Y' SET @CurrentCommand += ', TABLOCK' IF @MaxDOP IS NOT NULL SET @CurrentCommand += ', MAXDOP = ' + CAST(@MaxDOP AS nvarchar) @@ -6123,8 +6544,9 @@ BEGIN IF @LockTimeout IS NOT NULL SET @CurrentCommand = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand += 'DBCC CHECKFILEGROUP (' + QUOTENAME(@CurrentFileGroupName) IF @NoIndex = 'Y' SET @CurrentCommand += ', NOINDEX' - SET @CurrentCommand += ') WITH NO_INFOMSGS, ALL_ERRORMSGS' + SET @CurrentCommand += ') WITH ALL_ERRORMSGS' IF @PhysicalOnly = 'Y' SET @CurrentCommand += ', PHYSICAL_ONLY' + IF @NoInformationalMessages = 'Y' SET @CurrentCommand += ', NO_INFOMSGS' IF @TabLock = 'Y' SET @CurrentCommand += ', TABLOCK' IF @MaxDOP IS NOT NULL SET @CurrentCommand += ', MAXDOP = ' + CAST(@MaxDOP AS nvarchar) @@ -6162,7 +6584,8 @@ BEGIN SET @CurrentCommand = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand += 'DBCC CHECKALLOC (' + QUOTENAME(@CurrentDatabaseName) - SET @CurrentCommand += ') WITH NO_INFOMSGS, ALL_ERRORMSGS' + SET @CurrentCommand += ') WITH ALL_ERRORMSGS' + IF @NoInformationalMessages = 'Y' SET @CurrentCommand += ', NO_INFOMSGS' IF @TabLock = 'Y' SET @CurrentCommand += ', TABLOCK' EXECUTE @CurrentCommandOutput = dbo.CommandExecute @DatabaseContext = @CurrentDatabaseContext, @Command = @CurrentCommand, @CommandType = @CurrentCommandType, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute @@ -6290,10 +6713,11 @@ BEGIN IF @LockTimeout IS NOT NULL SET @CurrentCommand = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand += 'DBCC CHECKTABLE (' + QUOTENAME(QUOTENAME(@CurrentSchemaName) + '.' + QUOTENAME(@CurrentObjectName),'''') IF @NoIndex = 'Y' SET @CurrentCommand += ', NOINDEX' - SET @CurrentCommand += ') WITH NO_INFOMSGS, ALL_ERRORMSGS' + SET @CurrentCommand += ') WITH ALL_ERRORMSGS' IF @DataPurity = 'Y' SET @CurrentCommand += ', DATA_PURITY' IF @PhysicalOnly = 'Y' SET @CurrentCommand += ', PHYSICAL_ONLY' IF @ExtendedLogicalChecks = 'Y' SET @CurrentCommand += ', EXTENDED_LOGICAL_CHECKS' + IF @NoInformationalMessages = 'Y' SET @CurrentCommand += ', NO_INFOMSGS' IF @TabLock = 'Y' SET @CurrentCommand += ', TABLOCK' IF @MaxDOP IS NOT NULL SET @CurrentCommand += ', MAXDOP = ' + CAST(@MaxDOP AS nvarchar) @@ -6334,7 +6758,8 @@ BEGIN SET @CurrentCommand = '' IF @LockTimeout IS NOT NULL SET @CurrentCommand = 'SET LOCK_TIMEOUT ' + CAST(@LockTimeout * 1000 AS nvarchar) + '; ' SET @CurrentCommand += 'DBCC CHECKCATALOG (' + QUOTENAME(@CurrentDatabaseName) - SET @CurrentCommand += ') WITH NO_INFOMSGS' + SET @CurrentCommand += ')' + IF @NoInformationalMessages = 'Y' SET @CurrentCommand += ' WITH NO_INFOMSGS' EXECUTE @CurrentCommandOutput = dbo.CommandExecute @DatabaseContext = @CurrentDatabaseContext, @Command = @CurrentCommand, @CommandType = @CurrentCommandType, @Mode = 1, @DatabaseName = @CurrentDatabaseName, @LogToTable = @LogToTable, @Execute = @Execute SET @Error = @@ERROR @@ -6475,7 +6900,7 @@ BEGIN --// Source: https://ola.hallengren.com //-- --// License: https://ola.hallengren.com/license.html //-- --// GitHub: https://github.com/olahallengren/sql-server-maintenance-solution //-- - --// Version: 2024-12-27 18:10:28 //-- + --// Version: 2025-02-19 21:12:35 //-- ---------------------------------------------------------------------------------------------------- SET NOCOUNT ON @@ -6559,10 +6984,12 @@ BEGIN DECLARE @CurrentIsImageText bit DECLARE @CurrentIsNewLOB bit DECLARE @CurrentIsFileStream bit - DECLARE @CurrentIsColumnStore bit + DECLARE @CurrentHasColumnstore bit DECLARE @CurrentIsComputed bit + DECLARE @CurrentIsClusteredIndexComputed bit DECLARE @CurrentIsTimestamp bit DECLARE @CurrentAllowPageLocks bit + DECLARE @CurrentHasFilter bit DECLARE @CurrentNoRecompute bit DECLARE @CurrentIsIncremental bit DECLARE @CurrentRowCount bigint @@ -6609,11 +7036,13 @@ BEGIN IndexName nvarchar(max), IndexType int, AllowPageLocks bit, + HasFilter bit, IsImageText bit, IsNewLOB bit, IsFileStream bit, - IsColumnStore bit, + HasColumnstore bit, IsComputed bit, + IsClusteredIndexComputed bit, IsTimestamp bit, OnReadOnlyFileGroup bit, ResumableIndexOperation bit, @@ -6692,7 +7121,7 @@ BEGIN SET @HostPlatform = 'Windows' END - DECLARE @AmazonRDS bit = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END + DECLARE @AmazonRDS bit = CASE WHEN SERVERPROPERTY('EngineEdition') IN (5, 8) THEN 0 WHEN EXISTS (SELECT * FROM sys.databases WHERE [name] = 'rdsadmin') AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END ---------------------------------------------------------------------------------------------------- --// Log initial information //-- @@ -6749,7 +7178,7 @@ BEGIN SET @StartMessage = 'Platform: ' + @HostPlatform RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT - SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME(DB_ID())) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) + SET @StartMessage = 'Procedure: ' + QUOTENAME(DB_NAME()) + '.' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) RAISERROR('%s',10,1,@StartMessage) WITH NOWAIT SET @StartMessage = 'Parameters: ' + @Parameters @@ -6767,10 +7196,10 @@ BEGIN --// Check core requirements //-- ---------------------------------------------------------------------------------------------------- - IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE database_id = DB_ID()) >= 90 + IF NOT (SELECT [compatibility_level] FROM sys.databases WHERE [name] = DB_NAME()) >= 90 BEGIN INSERT INTO @Errors ([Message], Severity, [State]) - SELECT 'The database ' + QUOTENAME(DB_NAME(DB_ID())) + ' has to be in compatibility level 90 or higher.', 16, 1 + SELECT 'The database ' + QUOTENAME(DB_NAME()) + ' has to be in compatibility level 90 or higher.', 16, 1 END IF NOT (SELECT uses_ansi_nulls FROM sys.sql_modules WHERE [object_id] = @@PROCID) = 1 @@ -7851,14 +8280,6 @@ BEGIN SET @CurrentDatabase_sp_executesql = QUOTENAME(@CurrentDatabaseName) + '.sys.sp_executesql' - IF @ExecuteAsUser IS NOT NULL - BEGIN - SET @CurrentCommand = '' - SET @CurrentCommand += 'IF EXISTS(SELECT * FROM sys.database_principals database_principals WHERE database_principals.[name] = @ParamExecuteAsUser) BEGIN SET @ParamExecuteAsUserExists = 1 END ELSE BEGIN SET @ParamExecuteAsUserExists = 0 END' - - EXECUTE @CurrentDatabase_sp_executesql @stmt = @CurrentCommand, @params = N'@ParamExecuteAsUser sysname, @ParamExecuteAsUserExists bit OUTPUT', @ParamExecuteAsUser = @ExecuteAsUser, @ParamExecuteAsUserExists = @CurrentExecuteAsUserExists OUTPUT - END - BEGIN SET @DatabaseMessage = 'Date and time: ' + CONVERT(nvarchar,SYSDATETIME(),120) RAISERROR('%s',10,1,@DatabaseMessage) WITH NOWAIT @@ -7915,8 +8336,9 @@ BEGIN IF SERVERPROPERTY('EngineEdition') <> 5 BEGIN SELECT @CurrentDatabaseMirroringRole = UPPER(mirroring_role_desc) - FROM sys.database_mirroring - WHERE database_id = DB_ID(@CurrentDatabaseName) + FROM sys.database_mirroring database_mirroring + INNER JOIN sys.databases databases ON database_mirroring.database_id = databases.database_id + WHERE databases.[name] = @CurrentDatabaseName END IF @CurrentAvailabilityGroup IS NOT NULL @@ -7935,7 +8357,17 @@ BEGIN END RAISERROR(@EmptyLine,10,1) WITH NOWAIT + IF @ExecuteAsUser IS NOT NULL + AND @CurrentDatabaseState = 'ONLINE' + AND NOT (@CurrentUserAccess = 'SINGLE_USER') + AND NOT (@CurrentAvailabilityGroup IS NOT NULL AND (@CurrentAvailabilityGroupRole <> 'PRIMARY' OR @CurrentAvailabilityGroupRole IS NULL)) + AND NOT (@AmazonRDS = 1 AND @CurrentDatabaseName = 'rdsadmin') + BEGIN + SET @CurrentCommand = '' + SET @CurrentCommand += 'IF EXISTS(SELECT * FROM sys.database_principals database_principals WHERE database_principals.[name] = @ParamExecuteAsUser) BEGIN SET @ParamExecuteAsUserExists = 1 END ELSE BEGIN SET @ParamExecuteAsUserExists = 0 END' + EXECUTE @CurrentDatabase_sp_executesql @stmt = @CurrentCommand, @params = N'@ParamExecuteAsUser sysname, @ParamExecuteAsUserExists bit OUTPUT', @ParamExecuteAsUser = @ExecuteAsUser, @ParamExecuteAsUserExists = @CurrentExecuteAsUserExists OUTPUT + END IF @CurrentExecuteAsUserExists = 0 BEGIN SET @DatabaseMessage = 'The user ' + QUOTENAME(@ExecuteAsUser) + ' does not exist in the database ' + QUOTENAME(@CurrentDatabaseName) + '.' @@ -7946,6 +8378,8 @@ BEGIN IF @CurrentDatabaseState = 'ONLINE' AND NOT (@CurrentUserAccess = 'SINGLE_USER') AND NOT (@CurrentAvailabilityGroup IS NOT NULL AND (@CurrentAvailabilityGroupRole <> 'PRIMARY' OR @CurrentAvailabilityGroupRole IS NULL)) + AND NOT (@AmazonRDS = 1 AND @CurrentDatabaseName = 'rdsadmin') + AND NOT (@CurrentIsReadOnly = 1) AND (@CurrentExecuteAsUserExists = 1 OR @CurrentExecuteAsUserExists IS NULL) BEGIN @@ -7953,7 +8387,7 @@ BEGIN IF (EXISTS(SELECT * FROM @ActionsPreferred) OR @UpdateStatistics IS NOT NULL) AND (SYSDATETIME() < DATEADD(SECOND,@TimeLimit,@StartTime) OR @TimeLimit IS NULL) BEGIN SET @CurrentCommand = 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;' - + ' SELECT SchemaID, SchemaName, ObjectID, ObjectName, ObjectType, IsMemoryOptimized, IndexID, IndexName, IndexType, AllowPageLocks, IsImageText, IsNewLOB, IsFileStream, IsColumnStore, IsComputed, IsTimestamp, OnReadOnlyFileGroup, ResumableIndexOperation, StatisticsID, StatisticsName, NoRecompute, IsIncremental, PartitionID, PartitionNumber, PartitionCount, [Order], Selected, Completed' + + ' SELECT SchemaID, SchemaName, ObjectID, ObjectName, ObjectType, IsMemoryOptimized, IndexID, IndexName, IndexType, AllowPageLocks, HasFilter, IsImageText, IsNewLOB, IsFileStream, HasColumnstore, IsComputed, IsClusteredIndexComputed, IsTimestamp, OnReadOnlyFileGroup, ResumableIndexOperation, StatisticsID, StatisticsName, NoRecompute, IsIncremental, PartitionID, PartitionNumber, PartitionCount, [Order], Selected, Completed' + ' FROM (' IF EXISTS(SELECT * FROM @ActionsPreferred) OR @UpdateStatistics IN('ALL','INDEX') @@ -7968,6 +8402,7 @@ BEGIN + ', indexes.[name] AS IndexName' + ', indexes.[type] AS IndexType' + ', indexes.allow_page_locks AS AllowPageLocks' + + ', indexes.has_filter AS HasFilter' + ', CASE WHEN indexes.[type] = 1 AND EXISTS(SELECT * FROM sys.columns columns INNER JOIN sys.types types ON columns.system_type_id = types.user_type_id WHERE columns.[object_id] = objects.object_id AND types.name IN(''image'',''text'',''ntext'')) THEN 1 ELSE 0 END AS IsImageText' @@ -7976,17 +8411,18 @@ BEGIN + ', CASE WHEN indexes.[type] = 1 AND EXISTS(SELECT * FROM sys.columns columns WHERE columns.[object_id] = objects.object_id AND columns.is_filestream = 1) THEN 1 ELSE 0 END AS IsFileStream' - + ', CASE WHEN EXISTS(SELECT * FROM sys.indexes indexes WHERE indexes.[object_id] = objects.object_id AND [type] IN(5,6)) THEN 1 ELSE 0 END AS IsColumnStore' + + ', CASE WHEN EXISTS(SELECT * FROM sys.indexes indexes WHERE indexes.[object_id] = objects.object_id AND [type] IN(5,6)) THEN 1 ELSE 0 END AS HasColumnstore' + ', CASE WHEN EXISTS(SELECT * FROM sys.index_columns index_columns INNER JOIN sys.columns columns ON index_columns.object_id = columns.object_id AND index_columns.column_id = columns.column_id WHERE (index_columns.key_ordinal > 0 OR index_columns.partition_ordinal > 0) AND columns.is_computed = 1 AND index_columns.object_id = indexes.object_id AND index_columns.index_id = indexes.index_id) THEN 1 ELSE 0 END AS IsComputed' + + ', CASE WHEN EXISTS(SELECT * FROM sys.index_columns index_columns INNER JOIN sys.columns columns ON index_columns.object_id = columns.object_id AND index_columns.column_id = columns.column_id INNER JOIN sys.indexes indexes2 ON index_columns.object_id = indexes2.object_id AND index_columns.index_id = indexes2.index_id WHERE (index_columns.key_ordinal > 0 OR index_columns.partition_ordinal > 0) AND columns.is_computed = 1 AND indexes2.[type] = 1 AND index_columns.object_id = indexes.object_id) THEN 1 ELSE 0 END AS IsClusteredIndexComputed' + ', CASE WHEN EXISTS(SELECT * FROM sys.index_columns index_columns INNER JOIN sys.columns columns ON index_columns.[object_id] = columns.[object_id] AND index_columns.column_id = columns.column_id INNER JOIN sys.types types ON columns.system_type_id = types.system_type_id WHERE index_columns.[object_id] = objects.object_id AND index_columns.index_id = indexes.index_id AND types.[name] = ''timestamp'') THEN 1 ELSE 0 END AS IsTimestamp' + ', CASE WHEN EXISTS (SELECT * FROM sys.indexes indexes2 INNER JOIN sys.destination_data_spaces destination_data_spaces ON indexes.data_space_id = destination_data_spaces.partition_scheme_id INNER JOIN sys.filegroups filegroups ON destination_data_spaces.data_space_id = filegroups.data_space_id WHERE filegroups.is_read_only = 1 AND indexes2.[object_id] = indexes.[object_id] AND indexes2.[index_id] = indexes.index_id' + CASE WHEN @PartitionLevel = 'Y' THEN ' AND destination_data_spaces.destination_id = partitions.partition_number' ELSE '' END + ') THEN 1' + ' WHEN EXISTS (SELECT * FROM sys.indexes indexes2 INNER JOIN sys.filegroups filegroups ON indexes.data_space_id = filegroups.data_space_id WHERE filegroups.is_read_only = 1 AND indexes.[object_id] = indexes2.[object_id] AND indexes.[index_id] = indexes2.index_id) THEN 1' + ' WHEN indexes.[type] = 1 AND EXISTS (SELECT * FROM sys.tables tables INNER JOIN sys.filegroups filegroups ON tables.lob_data_space_id = filegroups.data_space_id WHERE filegroups.is_read_only = 1 AND tables.[object_id] = objects.[object_id]) THEN 1 ELSE 0 END AS OnReadOnlyFileGroup' - + ', ' + CASE WHEN @Version >= 14 THEN 'CASE WHEN EXISTS(SELECT * FROM sys.index_resumable_operations index_resumable_operations WHERE state_desc = ''PAUSED'' AND index_resumable_operations.object_id = indexes.object_id AND index_resumable_operations.index_id = indexes.index_id AND (index_resumable_operations.partition_number = partitions.partition_number OR index_resumable_operations.partition_number IS NULL)) THEN 1 ELSE 0 END' ELSE '0' END + ' AS ResumableIndexOperation' + + ', ' + CASE WHEN @Version >= 14 OR SERVERPROPERTY('EngineEdition') IN (5, 8) THEN 'CASE WHEN EXISTS(SELECT * FROM sys.index_resumable_operations index_resumable_operations WHERE state_desc = ''PAUSED'' AND index_resumable_operations.object_id = indexes.object_id AND index_resumable_operations.index_id = indexes.index_id' + CASE WHEN @PartitionLevel = 'Y' THEN ' AND (index_resumable_operations.partition_number = partitions.partition_number OR index_resumable_operations.partition_number IS NULL)' ELSE '' END + ') THEN 1 ELSE 0 END' ELSE '0' END + ' AS ResumableIndexOperation' + ', stats.stats_id AS StatisticsID' + ', stats.name AS StatisticsName' @@ -8031,11 +8467,13 @@ BEGIN + ', NULL AS IndexID, NULL AS IndexName' + ', NULL AS IndexType' + ', NULL AS AllowPageLocks' + + ', NULL AS HasFilter' + ', NULL AS IsImageText' + ', NULL AS IsNewLOB' + ', NULL AS IsFileStream' - + ', NULL AS IsColumnStore' + + ', NULL AS HasColumnstore' + ', NULL AS IsComputed' + + ', NULL AS IsClusteredIndexComputed' + ', NULL AS IsTimestamp' + ', NULL AS OnReadOnlyFileGroup' + ', NULL AS ResumableIndexOperation' @@ -8060,13 +8498,59 @@ BEGIN END SET @CurrentCommand = @CurrentCommand + ' WHERE objects.[type] IN(''U'',''V'')' + + CASE WHEN @Version >= 12 THEN ' AND (tables.is_memory_optimized = 0 OR tables.is_memory_optimized IS NULL)' ELSE '' END + CASE WHEN @MSShippedObjects = 'N' THEN ' AND objects.is_ms_shipped = 0' ELSE '' END + ' AND NOT EXISTS(SELECT * FROM sys.indexes indexes WHERE indexes.[object_id] = stats.[object_id] AND indexes.index_id = stats.stats_id)' + + ' AND NOT EXISTS(SELECT * FROM sys.indexes indexes2 WHERE indexes2.[object_id] = stats.[object_id] AND indexes2.type = 1 AND indexes2.is_disabled = 1)' + + IF @Version >= 12 + BEGIN + SET @CurrentCommand = @CurrentCommand + ' UNION ' + + SET @CurrentCommand = @CurrentCommand + 'SELECT schemas.[schema_id] AS SchemaID' + + ', schemas.[name] AS SchemaName' + + ', objects.[object_id] AS ObjectID' + + ', objects.[name] AS ObjectName' + + ', RTRIM(objects.[type]) AS ObjectType' + + ', tables.is_memory_optimized AS IsMemoryOptimized' + + ', NULL AS IndexID, NULL AS IndexName' + + ', NULL AS IndexType' + + ', NULL AS AllowPageLocks' + + ', NULL AS HasFilter' + + ', NULL AS IsImageText' + + ', NULL AS IsNewLOB' + + ', NULL AS IsFileStream' + + ', NULL AS HasColumnstore' + + ', NULL AS IsComputed' + + ', NULL AS IsClusteredIndexComputed' + + ', NULL AS IsTimestamp' + + ', NULL AS OnReadOnlyFileGroup' + + ', NULL AS ResumableIndexOperation' + + ', stats.stats_id AS StatisticsID' + + ', stats.name AS StatisticsName' + + ', stats.no_recompute AS NoRecompute' + + ', ' + CASE WHEN @Version >= 12 THEN 'stats.is_incremental' ELSE '0' END + ' AS IsIncremental' + + ', NULL AS PartitionID' + + ', NULL AS PartitionNumber' + + ', NULL AS PartitionCount' + + ', 0 AS [Order]' + + ', 0 AS Selected' + + ', 0 AS Completed' + + ' FROM sys.stats stats' + + ' INNER JOIN sys.objects objects ON stats.[object_id] = objects.[object_id]' + + ' INNER JOIN sys.schemas schemas ON objects.[schema_id] = schemas.[schema_id]' + + ' INNER JOIN sys.tables tables ON objects.[object_id] = tables.[object_id]' + + SET @CurrentCommand = @CurrentCommand + ' WHERE objects.[type] = ''U''' + + ' AND tables.is_memory_optimized = 1' + + CASE WHEN @MSShippedObjects = 'N' THEN ' AND objects.is_ms_shipped = 0' ELSE '' END + + ' AND NOT EXISTS(SELECT * FROM sys.indexes indexes WHERE indexes.[object_id] = stats.[object_id] AND indexes.index_id = stats.stats_id)' + END END SET @CurrentCommand = @CurrentCommand + ') IndexesStatistics' - INSERT INTO @tmpIndexesStatistics (SchemaID, SchemaName, ObjectID, ObjectName, ObjectType, IsMemoryOptimized, IndexID, IndexName, IndexType, AllowPageLocks, IsImageText, IsNewLOB, IsFileStream, IsColumnStore, IsComputed, IsTimestamp, OnReadOnlyFileGroup, ResumableIndexOperation, StatisticsID, StatisticsName, [NoRecompute], IsIncremental, PartitionID, PartitionNumber, PartitionCount, [Order], Selected, Completed) + INSERT INTO @tmpIndexesStatistics (SchemaID, SchemaName, ObjectID, ObjectName, ObjectType, IsMemoryOptimized, IndexID, IndexName, IndexType, AllowPageLocks, HasFilter, IsImageText, IsNewLOB, IsFileStream, HasColumnstore, IsComputed, IsClusteredIndexComputed, IsTimestamp, OnReadOnlyFileGroup, ResumableIndexOperation, StatisticsID, StatisticsName, [NoRecompute], IsIncremental, PartitionID, PartitionNumber, PartitionCount, [Order], Selected, Completed) EXECUTE @CurrentDatabase_sp_executesql @stmt = @CurrentCommand SET @Error = @@ERROR IF @Error <> 0 @@ -8166,11 +8650,13 @@ BEGIN @CurrentIndexName = IndexName, @CurrentIndexType = IndexType, @CurrentAllowPageLocks = AllowPageLocks, + @CurrentHasFilter = HasFilter, @CurrentIsImageText = IsImageText, @CurrentIsNewLOB = IsNewLOB, @CurrentIsFileStream = IsFileStream, - @CurrentIsColumnStore = IsColumnStore, + @CurrentHasColumnstore = HasColumnstore, @CurrentIsComputed = IsComputed, + @CurrentIsClusteredIndexComputed = IsClusteredIndexComputed, @CurrentIsTimestamp = IsTimestamp, @CurrentOnReadOnlyFileGroup = OnReadOnlyFileGroup, @CurrentResumableIndexOperation = ResumableIndexOperation, @@ -8308,6 +8794,7 @@ BEGIN AND @CurrentOnReadOnlyFileGroup = 0 AND EXISTS(SELECT * FROM @ActionsPreferred) AND (EXISTS(SELECT [Priority], [Action], COUNT(*) FROM @ActionsPreferred GROUP BY [Priority], [Action] HAVING COUNT(*) <> 3) OR @MinNumberOfPages > 0 OR @MaxNumberOfPages IS NOT NULL) + AND NOT (SERVERPROPERTY('EngineEdition') = 8 AND @CurrentDatabaseName IN ('master', 'model')) BEGIN SET @CurrentCommand = '' @@ -8346,25 +8833,33 @@ BEGIN -- Which actions are allowed? IF @CurrentIndexID IS NOT NULL AND EXISTS(SELECT * FROM @ActionsPreferred) BEGIN - IF @CurrentOnReadOnlyFileGroup = 0 AND @CurrentIndexType IN (1,2,3,4,5) AND (@CurrentIsMemoryOptimized = 0 OR @CurrentIsMemoryOptimized IS NULL) AND (@CurrentAllowPageLocks = 1 OR @CurrentIndexType = 5) + IF NOT (@CurrentOnReadOnlyFileGroup = 1) + AND NOT (@CurrentIsMemoryOptimized = 1) + AND NOT (@CurrentAllowPageLocks = 0) BEGIN INSERT INTO @CurrentActionsAllowed ([Action]) VALUES ('INDEX_REORGANIZE') END - IF @CurrentOnReadOnlyFileGroup = 0 AND @CurrentIndexType IN (1,2,3,4,5) AND (@CurrentIsMemoryOptimized = 0 OR @CurrentIsMemoryOptimized IS NULL) + IF NOT (@CurrentOnReadOnlyFileGroup = 1) + AND NOT (@CurrentIsMemoryOptimized = 1) BEGIN INSERT INTO @CurrentActionsAllowed ([Action]) VALUES ('INDEX_REBUILD_OFFLINE') END - IF @CurrentOnReadOnlyFileGroup = 0 - AND (@CurrentIsMemoryOptimized = 0 OR @CurrentIsMemoryOptimized IS NULL) - AND (@CurrentIsPartition = 0 OR @Version >= 12) - AND ((@CurrentIndexType = 1 AND @CurrentIsImageText = 0 AND @CurrentIsNewLOB = 0) - OR (@CurrentIndexType = 2 AND @CurrentIsNewLOB = 0) - OR (@CurrentIndexType = 1 AND @CurrentIsImageText = 0 AND @CurrentIsFileStream = 0 AND @Version >= 11) - OR (@CurrentIndexType = 2 AND @Version >= 11)) - AND (@CurrentIsColumnStore = 0 OR @Version < 11) - AND SERVERPROPERTY('EngineEdition') IN (3,5,8) + IF SERVERPROPERTY('EngineEdition') IN (3, 5, 8) + AND NOT (@CurrentOnReadOnlyFileGroup = 1) + AND NOT (@CurrentIsMemoryOptimized = 1) + AND NOT (@CurrentIsPartition = 1 AND @Version < 12) + AND NOT (@CurrentIndexType = 1 AND @CurrentIsImageText = 1) + AND NOT (@CurrentIndexType = 1 AND @CurrentIsFileStream = 1) + AND NOT (@CurrentIndexType = 1 AND @CurrentIsNewLOB = 1 AND @Version < 11) + AND NOT (@CurrentIndexType = 2 AND @CurrentIsNewLOB = 1 AND @Version < 11) + AND NOT (@CurrentIndexType = 3) + AND NOT (@CurrentIndexType = 4) + AND NOT (@CurrentIndexType = 5 AND @Version < 15) + AND NOT (@CurrentIndexType = 6 AND @Version < 15) + AND NOT (@CurrentIndexType = 1 AND @CurrentHasColumnstore = 1 AND @Version < 13) + AND NOT (@CurrentIndexType = 2 AND @CurrentHasColumnstore = 1 AND @Version < 13) BEGIN INSERT INTO @CurrentActionsAllowed ([Action]) VALUES ('INDEX_REBUILD_ONLINE') @@ -8452,9 +8947,11 @@ BEGIN SET @CurrentComment += 'ImageText: ' + CASE WHEN @CurrentIsImageText = 1 THEN 'Yes' WHEN @CurrentIsImageText = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment += 'NewLOB: ' + CASE WHEN @CurrentIsNewLOB = 1 THEN 'Yes' WHEN @CurrentIsNewLOB = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment += 'FileStream: ' + CASE WHEN @CurrentIsFileStream = 1 THEN 'Yes' WHEN @CurrentIsFileStream = 0 THEN 'No' ELSE 'N/A' END + ', ' - IF @Version >= 11 SET @CurrentComment += 'ColumnStore: ' + CASE WHEN @CurrentIsColumnStore = 1 THEN 'Yes' WHEN @CurrentIsColumnStore = 0 THEN 'No' ELSE 'N/A' END + ', ' + IF @Version >= 11 SET @CurrentComment += 'HasColumnStore: ' + CASE WHEN @CurrentHasColumnstore = 1 THEN 'Yes' WHEN @CurrentHasColumnstore = 0 THEN 'No' ELSE 'N/A' END + ', ' IF @Version >= 14 AND @Resumable = 'Y' SET @CurrentComment += 'Computed: ' + CASE WHEN @CurrentIsComputed = 1 THEN 'Yes' WHEN @CurrentIsComputed = 0 THEN 'No' ELSE 'N/A' END + ', ' + IF @Version >= 14 AND @Resumable = 'Y' AND @CurrentIndexType = 2 SET @CurrentComment += 'ClusteredIndexComputed: ' + CASE WHEN @CurrentIsClusteredIndexComputed = 1 THEN 'Yes' WHEN @CurrentIsClusteredIndexComputed = 0 THEN 'No' ELSE 'N/A' END + ', ' IF @Version >= 14 AND @Resumable = 'Y' SET @CurrentComment += 'Timestamp: ' + CASE WHEN @CurrentIsTimestamp = 1 THEN 'Yes' WHEN @CurrentIsTimestamp = 0 THEN 'No' ELSE 'N/A' END + ', ' + IF @Version >= 14 AND @Resumable = 'Y' SET @CurrentComment += 'HasFilter: ' + CASE WHEN @CurrentHasFilter = 1 THEN 'Yes' WHEN @CurrentHasFilter = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment += 'AllowPageLocks: ' + CASE WHEN @CurrentAllowPageLocks = 1 THEN 'Yes' WHEN @CurrentAllowPageLocks = 0 THEN 'No' ELSE 'N/A' END + ', ' SET @CurrentComment += 'PageCount: ' + ISNULL(CAST(@CurrentPageCount AS nvarchar),'N/A') + ', ' SET @CurrentComment += 'Fragmentation: ' + ISNULL(CAST(@CurrentFragmentationLevel AS nvarchar),'N/A') @@ -8527,10 +9024,10 @@ BEGIN IF (@Version >= 14 OR SERVERPROPERTY('EngineEdition') IN (5,8)) AND @CurrentAction = 'INDEX_REBUILD_ONLINE' AND @CurrentResumableIndexOperation = 0 BEGIN INSERT INTO @CurrentAlterIndexWithClauseArguments (Argument) - SELECT CASE WHEN @Resumable = 'Y' AND @CurrentIndexType IN(1,2) AND @CurrentIsComputed = 0 AND @CurrentIsTimestamp = 0 THEN 'RESUMABLE = ON' ELSE 'RESUMABLE = OFF' END + SELECT CASE WHEN @Resumable = 'Y' AND @CurrentIndexType IN(1,2) AND @CurrentIsComputed = 0 AND @CurrentIsClusteredIndexComputed = 0 AND @CurrentIsTimestamp = 0 AND @CurrentHasFilter = 0 THEN 'RESUMABLE = ON' ELSE 'RESUMABLE = OFF' END END - IF (@Version >= 14 OR SERVERPROPERTY('EngineEdition') IN (5,8)) AND @CurrentAction = 'INDEX_REBUILD_ONLINE' AND @CurrentResumableIndexOperation = 0 AND @Resumable = 'Y' AND @CurrentIndexType IN(1,2) AND @CurrentIsComputed = 0 AND @CurrentIsTimestamp = 0 AND @TimeLimit IS NOT NULL + IF (@Version >= 14 OR SERVERPROPERTY('EngineEdition') IN (5,8)) AND @CurrentAction = 'INDEX_REBUILD_ONLINE' AND @Resumable = 'Y' AND @CurrentIndexType IN(1,2) AND @CurrentIsComputed = 0 AND @CurrentIsClusteredIndexComputed = 0 AND @CurrentIsTimestamp = 0 AND @CurrentHasFilter = 0 AND @TimeLimit IS NOT NULL BEGIN INSERT INTO @CurrentAlterIndexWithClauseArguments (Argument) SELECT 'MAX_DURATION = ' + CAST(DATEDIFF(MINUTE,SYSDATETIME(),DATEADD(SECOND,@TimeLimit,@StartTime)) AS nvarchar(max)) @@ -8642,16 +9139,16 @@ BEGIN SELECT 'SAMPLE ' + CAST(@CurrentStatisticsSample AS nvarchar) + ' PERCENT' END - IF @CurrentStatisticsResample = 'Y' + IF @CurrentNoRecompute = 1 BEGIN INSERT INTO @CurrentUpdateStatisticsWithClauseArguments (Argument) - SELECT 'RESAMPLE' + SELECT 'NORECOMPUTE' END - IF @CurrentNoRecompute = 1 + IF @CurrentStatisticsResample = 'Y' BEGIN INSERT INTO @CurrentUpdateStatisticsWithClauseArguments (Argument) - SELECT 'NORECOMPUTE' + SELECT 'RESAMPLE' END IF EXISTS (SELECT * FROM @CurrentUpdateStatisticsWithClauseArguments) @@ -8732,10 +9229,12 @@ BEGIN SET @CurrentIsImageText = NULL SET @CurrentIsNewLOB = NULL SET @CurrentIsFileStream = NULL - SET @CurrentIsColumnStore = NULL + SET @CurrentHasColumnstore = NULL SET @CurrentIsComputed = NULL + SET @CurrentIsClusteredIndexComputed = NULL SET @CurrentIsTimestamp = NULL SET @CurrentAllowPageLocks = NULL + SET @CurrentHasFilter = NULL SET @CurrentNoRecompute = NULL SET @CurrentIsIncremental = NULL SET @CurrentRowCount = NULL @@ -8837,8 +9336,8 @@ END GO IF (SELECT [Value] FROM #Config WHERE Name = 'CreateJobs') = 'Y' AND SERVERPROPERTY('EngineEdition') NOT IN(4, 5) - AND (IS_SRVROLEMEMBER('sysadmin') = 1 OR (DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa')) - AND (SELECT [compatibility_level] FROM sys.databases WHERE database_id = DB_ID()) >= 90 + AND (IS_SRVROLEMEMBER('sysadmin') = 1 OR (EXISTS (SELECT * FROM sys.databases WHERE [name] = 'rdsadmin') AND SUSER_SNAME(0x01) = 'rdsa')) + AND (SELECT [compatibility_level] FROM sys.databases WHERE [name] = DB_NAME()) >= 90 AND NOT (EXISTS (SELECT * FROM #Config WHERE Name = 'BackupDirectory' AND [Value] IS NOT NULL) AND EXISTS (SELECT * FROM #Config WHERE Name = 'BackupURL' AND [Value] IS NOT NULL)) AND NOT (EXISTS (SELECT * FROM #Config WHERE Name = 'BackupURL' AND [Value] IS NOT NULL) AND EXISTS (SELECT * FROM #Config WHERE Name = 'CleanupTime' AND [Value] IS NOT NULL)) BEGIN @@ -8892,7 +9391,14 @@ BEGIN DECLARE @Version numeric(18,10) = CAST(LEFT(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)),CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max))) - 1) + '.' + REPLACE(RIGHT(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)), LEN(CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max))) - CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(max)))),'.','') AS numeric(18,10)) - DECLARE @AmazonRDS bit = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END + DECLARE @AmazonRDS bit = CASE WHEN SERVERPROPERTY('EngineEdition') IN (5, 8) THEN 0 WHEN EXISTS (SELECT * FROM sys.databases WHERE [name] = 'rdsadmin') AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END + + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + DECLARE @S3BucketArn nvarchar(max) + DECLARE @kms_master_key_arn nvarchar(max) + ---------------------------------------------------------------------------------------------------- IF @Version >= 14 BEGIN @@ -8946,6 +9452,18 @@ BEGIN FROM #Config WHERE [Name] = 'LogToTable' + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + SELECT @S3BucketArn = Value + FROM #Config + WHERE [Name] = 'S3BucketArn' + + SELECT @kms_master_key_arn = Value + FROM #Config + WHERE [Name] = 'kms_master_key_arn' + ---------------------------------------------------------------------------------------------------- + SELECT @DatabaseName = Value FROM #Config WHERE [Name] = 'DatabaseName' @@ -8980,28 +9498,28 @@ BEGIN INSERT INTO @Jobs ([Name], CommandTSQL, DatabaseName, OutputFileNamePart01, OutputFileNamePart02) SELECT 'DatabaseBackup - SYSTEM_DATABASES - FULL', - 'EXECUTE [dbo].[DatabaseBackup]' + CHAR(13) + CHAR(10) + '@Databases = ''SYSTEM_DATABASES'',' + CHAR(13) + CHAR(10) + CASE WHEN @BackupURL IS NOT NULL THEN '@URL = N''' + REPLACE(@BackupURL,'''','''''') + '''' ELSE '@Directory = ' + ISNULL('N''' + REPLACE(@BackupDirectory,'''','''''') + '''','NULL') END + ',' + CHAR(13) + CHAR(10) + '@BackupType = ''FULL'',' + CHAR(13) + CHAR(10) + '@Verify = ''Y'',' + CHAR(13) + CHAR(10) + '@CleanupTime = ' + ISNULL(CAST(@CleanupTime AS nvarchar),'NULL') + ',' + CHAR(13) + CHAR(10) + '@CheckSum = ''Y'',' + CHAR(13) + CHAR(10) + '@LogToTable = ''' + @LogToTable + '''', + 'EXECUTE [dbo].[DatabaseBackup]' + CHAR(13) + CHAR(10) + '@Databases = ''SYSTEM_DATABASES'',' + CHAR(13) + CHAR(10) + CASE WHEN @BackupURL IS NOT NULL THEN '@URL = N''' + REPLACE(@BackupURL,'''','''''') + '''' ELSE '@Directory = ' + ISNULL('N''' + REPLACE(@BackupDirectory,'''','''''') + '''','NULL') END + ',' + CHAR(13) + CHAR(10) + '@BackupType = ''FULL'',' + CHAR(13) + CHAR(10) + '@Verify = ''Y'',' + CHAR(13) + CHAR(10) + '@CleanupTime = ' + ISNULL(CAST(@CleanupTime AS nvarchar),'NULL') + ',' + CHAR(13) + CHAR(10) + '@Checksum = ''Y'',' + CHAR(13) + CHAR(10) + '@LogToTable = ''' + @LogToTable + '''', @DatabaseName, 'DatabaseBackup', 'FULL' INSERT INTO @Jobs ([Name], CommandTSQL, DatabaseName, OutputFileNamePart01, OutputFileNamePart02) SELECT 'DatabaseBackup - USER_DATABASES - DIFF', - 'EXECUTE [dbo].[DatabaseBackup]' + CHAR(13) + CHAR(10) + '@Databases = ''USER_DATABASES'',' + CHAR(13) + CHAR(10) + CASE WHEN @BackupURL IS NOT NULL THEN '@URL = N''' + REPLACE(@BackupURL,'''','''''') + '''' ELSE '@Directory = ' + ISNULL('N''' + REPLACE(@BackupDirectory,'''','''''') + '''','NULL') END + ',' + CHAR(13) + CHAR(10) + '@BackupType = ''DIFF'',' + CHAR(13) + CHAR(10) + '@Verify = ''Y'',' + CHAR(13) + CHAR(10) + '@CleanupTime = ' + ISNULL(CAST(@CleanupTime AS nvarchar),'NULL') + ',' + CHAR(13) + CHAR(10) + '@CheckSum = ''Y'',' + CHAR(13) + CHAR(10) + '@LogToTable = ''' + @LogToTable + '''', + 'EXECUTE [dbo].[DatabaseBackup]' + CHAR(13) + CHAR(10) + '@Databases = ''USER_DATABASES' + CASE WHEN @AmazonRDS = 1 THEN ', -rdsadmin%' ELSE '' END + ''',' + CHAR(13) + CHAR(10) + CASE WHEN @BackupURL IS NOT NULL THEN '@URL = N''' + REPLACE(@BackupURL,'''','''''') + '''' ELSE '@Directory = ' + ISNULL('N''' + REPLACE(@BackupDirectory,'''','''''') + '''','NULL') END + ',' + CHAR(13) + CHAR(10) + '@BackupType = ''DIFF'',' + CHAR(13) + CHAR(10) + '@Verify = ''Y'',' + CHAR(13) + CHAR(10) + '@CleanupTime = ' + ISNULL(CAST(@CleanupTime AS nvarchar),'NULL') + ',' + CHAR(13) + CHAR(10) + '@Checksum = ''Y'',' + CHAR(13) + CHAR(10) + CASE WHEN @AmazonRDS = 1 THEN '@S3BucketArn = ' + ISNULL('N''' + REPLACE(@S3BucketArn,'''','''''') + '''','NULL') + ',' + CHAR(13) + CHAR(10) ELSE '' END + CASE WHEN @AmazonRDS = 1 THEN '@kms_master_key_arn = ' + ISNULL('N''' + REPLACE(@kms_master_key_arn,'''','''''') + '''','NULL') + ',' + CHAR(13) + CHAR(10) ELSE '' END + '@LogToTable = ''' + @LogToTable + '''', @DatabaseName, 'DatabaseBackup', 'DIFF' INSERT INTO @Jobs ([Name], CommandTSQL, DatabaseName, OutputFileNamePart01, OutputFileNamePart02) SELECT 'DatabaseBackup - USER_DATABASES - FULL', - 'EXECUTE [dbo].[DatabaseBackup]' + CHAR(13) + CHAR(10) + '@Databases = ''USER_DATABASES'',' + CHAR(13) + CHAR(10) + CASE WHEN @BackupURL IS NOT NULL THEN '@URL = N''' + REPLACE(@BackupURL,'''','''''') + '''' ELSE '@Directory = ' + ISNULL('N''' + REPLACE(@BackupDirectory,'''','''''') + '''','NULL') END + ',' + CHAR(13) + CHAR(10) + '@BackupType = ''FULL'',' + CHAR(13) + CHAR(10) + '@Verify = ''Y'',' + CHAR(13) + CHAR(10) + '@CleanupTime = ' + ISNULL(CAST(@CleanupTime AS nvarchar),'NULL') + ',' + CHAR(13) + CHAR(10) + '@CheckSum = ''Y'',' + CHAR(13) + CHAR(10) + '@LogToTable = ''' + @LogToTable + '''', + 'EXECUTE [dbo].[DatabaseBackup]' + CHAR(13) + CHAR(10) + '@Databases = ''USER_DATABASES' + CASE WHEN @AmazonRDS = 1 THEN ', -rdsadmin%' ELSE '' END + ''',' + CHAR(13) + CHAR(10) + CASE WHEN @BackupURL IS NOT NULL THEN '@URL = N''' + REPLACE(@BackupURL,'''','''''') + '''' ELSE '@Directory = ' + ISNULL('N''' + REPLACE(@BackupDirectory,'''','''''') + '''','NULL') END + ',' + CHAR(13) + CHAR(10) + '@BackupType = ''FULL'',' + CHAR(13) + CHAR(10) + '@Verify = ''Y'',' + CHAR(13) + CHAR(10) + '@CleanupTime = ' + ISNULL(CAST(@CleanupTime AS nvarchar),'NULL') + ',' + CHAR(13) + CHAR(10) + '@Checksum = ''Y'',' + CHAR(13) + CHAR(10) + CASE WHEN @AmazonRDS = 1 THEN '@S3BucketArn = ' + ISNULL('N''' + REPLACE(@S3BucketArn,'''','''''') + '''','NULL') + ',' + CHAR(13) + CHAR(10) ELSE '' END + CASE WHEN @AmazonRDS = 1 THEN '@kms_master_key_arn = ' + ISNULL('N''' + REPLACE(@kms_master_key_arn,'''','''''') + '''','NULL') + ',' + CHAR(13) + CHAR(10) ELSE '' END + '@LogToTable = ''' + @LogToTable + '''', @DatabaseName, 'DatabaseBackup', 'FULL' INSERT INTO @Jobs ([Name], CommandTSQL, DatabaseName, OutputFileNamePart01, OutputFileNamePart02) SELECT 'DatabaseBackup - USER_DATABASES - LOG', - 'EXECUTE [dbo].[DatabaseBackup]' + CHAR(13) + CHAR(10) + '@Databases = ''USER_DATABASES'',' + CHAR(13) + CHAR(10) + CASE WHEN @BackupURL IS NOT NULL THEN '@URL = N''' + REPLACE(@BackupURL,'''','''''') + '''' ELSE '@Directory = ' + ISNULL('N''' + REPLACE(@BackupDirectory,'''','''''') + '''','NULL') END + ',' + CHAR(13) + CHAR(10) + '@BackupType = ''LOG'',' + CHAR(13) + CHAR(10) + '@Verify = ''Y'',' + CHAR(13) + CHAR(10) + '@CleanupTime = ' + ISNULL(CAST(@CleanupTime AS nvarchar),'NULL') + ',' + CHAR(13) + CHAR(10) + '@CheckSum = ''Y'',' + CHAR(13) + CHAR(10) + '@LogToTable = ''' + @LogToTable + '''', + 'EXECUTE [dbo].[DatabaseBackup]' + CHAR(13) + CHAR(10) + '@Databases = ''USER_DATABASES' + CASE WHEN @AmazonRDS = 1 THEN ', -rdsadmin%' ELSE '' END + ''',' + CHAR(13) + CHAR(10) + CASE WHEN @BackupURL IS NOT NULL THEN '@URL = N''' + REPLACE(@BackupURL,'''','''''') + '''' ELSE '@Directory = ' + ISNULL('N''' + REPLACE(@BackupDirectory,'''','''''') + '''','NULL') END + ',' + CHAR(13) + CHAR(10) + '@BackupType = ''LOG'',' + CHAR(13) + CHAR(10) + '@Verify = ''Y'',' + CHAR(13) + CHAR(10) + '@CleanupTime = ' + ISNULL(CAST(@CleanupTime AS nvarchar),'NULL') + ',' + CHAR(13) + CHAR(10) + '@Checksum = ''Y'',' + CHAR(13) + CHAR(10) + '@LogToTable = ''' + @LogToTable + '''', @DatabaseName, 'DatabaseBackup', 'LOG' @@ -9018,11 +9536,15 @@ BEGIN @DatabaseName, 'DatabaseIntegrityCheck' + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- INSERT INTO @Jobs ([Name], CommandTSQL, DatabaseName, OutputFileNamePart01) SELECT 'IndexOptimize - USER_DATABASES', - 'EXECUTE [dbo].[IndexOptimize]' + CHAR(13) + CHAR(10) + '@Databases = ''USER_DATABASES'',' + CHAR(13) + CHAR(10) + '@LogToTable = ''' + @LogToTable + '''', + 'EXECUTE [dbo].[IndexOptimize]' + CHAR(13) + CHAR(10) + '@Databases = ''USER_DATABASES' + CASE WHEN @AmazonRDS = 1 THEN ', -rdsadmin' ELSE '' END + ''',' + CHAR(13) + CHAR(10) + '@LogToTable = ''' + @LogToTable + '''', @DatabaseName, 'IndexOptimize' + ---------------------------------------------------------------------------------------------------- INSERT INTO @Jobs ([Name], CommandTSQL, DatabaseName, OutputFileNamePart01) SELECT 'sp_delete_backuphistory', @@ -9047,11 +9569,71 @@ BEGIN 'cmd /q /c "For /F "tokens=1 delims=" %v In (''ForFiles /P "' + COALESCE(@OutputFileDirectory,@TokenLogDirectory,@LogDirectory) + '" /m *_*_*_*.txt /d -30 2^>^&1'') do if EXIST "' + COALESCE(@OutputFileDirectory,@TokenLogDirectory,@LogDirectory) + '"\%v echo del "' + COALESCE(@OutputFileDirectory,@TokenLogDirectory,@LogDirectory) + '"\%v& del "' + COALESCE(@OutputFileDirectory,@TokenLogDirectory,@LogDirectory) + '"\%v"', 'OutputFileCleanup' + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @AmazonRDS = 1 + BEGIN + INSERT INTO @Jobs ([Name], CommandTSQL, DatabaseName, OutputFileNamePart01) + SELECT 'DatabaseBackup - Check RDS Backup Status', + 'DECLARE @RDSQueue TABLE ([task_id] INT, + [task_type] nvarchar(max), + [database_name] nvarchar(max), + [% complete] nvarchar(max), + [duration (mins)] nvarchar(max), + [lifecycle] nvarchar(max), + [task_info] nvarchar(max), + [last_updated] nvarchar(max), + [created_at] nvarchar(max), + [S3_object_arn] nvarchar(max), + [overwrite_s3_backup_file] nvarchar(max), + [KMS_master_key_arn] nvarchar(max), + [filepath] nvarchar(max), + [overwrite_file] BIT) + + DECLARE @Message nvarchar(4000) = '''' + + INSERT INTO @RDSQueue exec msdb..rds_task_status + + IF EXISTS( SELECT rbl.ID, rbl.task_id, rbl.[Status], rq.lifecycle + FROM [RDS_BackupLog] rbl + INNER JOIN @RDSQueue rq ON rbl.task_id = rq.task_id + WHERE rq.lifecycle = ''ERROR'' AND rbl.[Status] <> rq.lifecycle ) + SET @Message = ''RDS:Msg Errors Detected in RDS Backup Queue Status'' + + select rq.task_id, rbl.ID , rq.[task_info] , rq.lifecycle INTO #tmp1 + FROM [RDS_BackupLog] rbl + INNER JOIN @RDSQueue rq ON rbl.task_id = rq.task_id + WHERE rbl.[Status] NOT IN (''SUCCESS'',''ERROR'') + + UPDATE CommandLog + SET CommandLog.ErrorNumber = 50000, CommandLog.ErrorMessage = #tmp1.[task_info] + FROM CommandLog cl + INNER JOIN #tmp1 ON cl.ID = #tmp1.ID + WHERE #tmp1.lifecycle = ''ERROR'' + + UPDATE [RDS_BackupLog] + SET [RDS_BackupLog].[Status] = rq.[lifecycle], [RDS_BackupLog].[task_info] = rq.[task_info] + FROM [RDS_BackupLog] + INNER JOIN @RDSQueue rq ON [RDS_BackupLog].task_id = rq.task_id + WHERE [RDS_BackupLog].[Status] NOT IN (''SUCCESS'',''ERROR'') + + IF @Message <> '''' + RAISERROR(''%s'',16,1,''RDS:Msg Errors Detected in RDS Backup Queue Status'') WITH LOG', + @DatabaseName, + 'CheckRDSBackupStatus' + END + ---------------------------------------------------------------------------------------------------- + IF @AmazonRDS = 1 BEGIN UPDATE @Jobs SET Selected = 1 - WHERE [Name] IN('DatabaseIntegrityCheck - USER_DATABASES','IndexOptimize - USER_DATABASES','CommandLog Cleanup') + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + WHERE [Name] IN('DatabaseIntegrityCheck - USER_DATABASES','IndexOptimize - USER_DATABASES','CommandLog Cleanup','DatabaseBackup - USER_DATABASES - FULL','DatabaseBackup - USER_DATABASES - DIFF','DatabaseBackup - Check RDS Backup Status') + ---------------------------------------------------------------------------------------------------- END ELSE IF SERVERPROPERTY('EngineEdition') = 8 BEGIN @@ -9130,6 +9712,15 @@ BEGIN IF LEN(@CurrentOutputFileName) > 200 SET @CurrentOutputFileName = NULL END + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- + IF @AmazonRDS = 1 + BEGIN + SET @CurrentOutputFileName = NULL + END + ---------------------------------------------------------------------------------------------------- + IF @CurrentJobStepSubSystem IS NOT NULL AND @CurrentJobStepCommand IS NOT NULL AND NOT EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE [name] = @CurrentJobName) BEGIN EXECUTE msdb.dbo.sp_add_job @job_name = @CurrentJobName, @description = @JobDescription, @category_name = @JobCategory, @owner_login_name = @JobOwner @@ -9159,3 +9750,57 @@ BEGIN END GO + ---------------------------------------------------------------------------------------------------- + --// Original Copyright 2024 Ola Hallengren. Licensed under the MIT License. //-- + --// Modifications Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. //-- +USE [msdb] +GO + +DECLARE @jobId BINARY(16) +DECLARE @ReturnCode INT + +SELECT @ReturnCode = 0 + +IF EXISTS (SELECT job_id FROM msdb.dbo.sysjobs WHERE name = N'DatabaseBackup - Check RDS Backup Status') +BEGIN + SELECT @jobId=job_id FROM msdb.dbo.sysjobs WHERE name = N'DatabaseBackup - Check RDS Backup Status' + EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'Every 5 Minutes', + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=4, + @freq_subday_interval=5, + @freq_relative_interval=0, + @freq_recurrence_factor=0, + @active_start_date=20000101, + @active_end_date=99991231, + @active_start_time=0, + @active_end_time=235959 +END + +DECLARE @AmazonRDS bit = CASE WHEN DB_ID('rdsadmin') IS NOT NULL AND SUSER_SNAME(0x01) = 'rdsa' THEN 1 ELSE 0 END +DECLARE @job_id uniqueidentifier +DECLARE @step_id int +DECLARE @command nvarchar(max) + +IF @AmazonRDS = 0 + BEGIN + DECLARE JobCursor CURSOR FAST_FORWARD FOR SELECT job_id, step_id, command FROM msdb.dbo.sysjobsteps WHERE command LIKE '%DatabaseBackup%@CheckSum%' COLLATE SQL_Latin1_General_CP1_CS_AS + + OPEN JobCursor + FETCH JobCursor INTO @job_id, @step_id, @command + + WHILE @@FETCH_STATUS = 0 + BEGIN + SET @command = REPLACE(@command, '@CheckSum', '@Checksum') + + EXECUTE msdb.dbo.sp_update_jobstep @job_id = @job_id, @step_id = @step_id, @command = @command + + FETCH NEXT FROM JobCursor INTO @job_id, @step_id, @command + END + + CLOSE JobCursor + DEALLOCATE JobCursor + END + ---------------------------------------------------------------------------------------------------- +GO \ No newline at end of file diff --git a/RDS_BackupLog.sql b/RDS_BackupLog.sql new file mode 100644 index 00000000..fea470fb --- /dev/null +++ b/RDS_BackupLog.sql @@ -0,0 +1,32 @@ +/* +MIT License + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[RDS_BackupLog]') AND type in (N'U')) +BEGIN +CREATE TABLE [dbo].[RDS_BackupLog]( + [ID] [int] NOT NULL, + [task_id] [int] NOT NULL, + [Status] [nvarchar](max) NULL, + [task_Info] [nvarchar](max) NULL, + CONSTRAINT [PK_RDS_BackupLog] PRIMARY KEY CLUSTERED +( + [ID] ASC, [task_id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) +GO + + diff --git a/README.md b/README.md index 9583a0e5..001094bf 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,12 @@ [![bug report badge]][bug report] [![feature request badge]][feature request] +## Notes regarding this Repo + +This fork from https://github.com/olahallengren/sql-server-maintenance-solution is to address requests for support to use Amazon RDS for SQL Server. + +This repo will accept pull requests related to that specific functionality but larger functionality requests should continue to be presented to the upstream repo as the owner of the original code. Unfortunately, we are a small team and do not have the bandwidth to review and accept PRs outside of this scope. + ## Getting Started Download [MaintenanceSolution.sql](/MaintenanceSolution.sql). @@ -21,7 +27,7 @@ You can also download the objects as separate scripts: Note that you always need CommandExecute; DatabaseBackup, DatabaseIntegrityCheck, and IndexOptimize are using it. You need CommandLog if you are going to use the option to log commands to a table. -Supported versions: SQL Server 2008, SQL Server 2008 R2, SQL Server 2012, SQL Server 2014, SQL Server 2016, SQL Server 2017, SQL Server 2019, SQL Server 2022, Azure SQL Database, and Azure SQL Managed Instance +Supported versions: SQL Server 2008, SQL Server 2008 R2, SQL Server 2012, SQL Server 2014, SQL Server 2016, SQL Server 2017, SQL Server 2019, SQL Server 2022, Azure SQL Database, Azure SQL Managed Instance and [Supported Amazon RDS for SQL Server Versions](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_SQLServer.html#SQLServer.Concepts.General.VersionSupport) ## Documentation @@ -29,18 +35,20 @@ Supported versions: SQL Server 2008, SQL Server 2008 R2, SQL Server 2012, SQL Se