oct
10
2015

Steve Stedman’s DBCC Challenge, Week-4 Second Alternate Solution

*First published @ Steve Stedman’s blog (2015/05/06)

The following is a solution to Corruption Challenge #4 that uses DBCC WritePage to fix the corruption.  Before proceeding, be sure to read this warning.

WARNING: DBCC WritePage is a dangerous command, that should never be used on any production database. It may invalidate your ability to get support from Microsoft on issues that arise with that database going forward. It is not my intention to encourage anyone to use DBCC WritePage ever. This is just what I used to create a corrupt database, and since creating corrupt databases is not part of the role of most DBAs, you should not use DBCC WritePage. Consider yourself warned.

DBCC WritePage is a cool, but extremely risky way to solve this weeks Database Corruption Challenge, however, do NOT EVER RUN THIS ON A PRODUCTION SYSTEM.

 

The Solution using DBCC WritePage

 

The following is the actual solution submitted by Raul Gonzalez for Week 4 of the Database Corruption Challenge.

USE master
GO
IF DB_ID('CorruptionChallenge4') IS NOT NULL BEGIN
    ALTER DATABASE CorruptionChallenge4 SET SINGLE_USER WITH ROLLBACK IMMEDIATE
    DROP DATABASE CorruptionChallenge4
END
GO
--RESTORE FILELISTONLY
--FROM DISK = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014\MSSQL\Backup\CorruptionChallenge4_Corrupt.bak'
 
-- Create folder C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\DATA\
-- grant permission to SQL Server service account
 
RESTORE DATABASE CorruptionChallenge4
FROM DISK = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014\MSSQL\Backup\CorruptionChallenge4_Corrupt.bak'
WITH NORECOVERY, REPLACE
    , MOVE 'CorruptionChallenge4' TO 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014\MSSQL\DATA\CorruptionChallenge4.mdf'
    , MOVE 'UserObjects' TO 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014\MSSQL\DATA\CorruptionChallenge4_UserObjects.ndf'
    , MOVE 'CorruptionChallenge4_log' TO 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014\MSSQL\DATA\CorruptionChallenge4_log.ldf'
GO
 
RESTORE DATABASE CorruptionChallenge4 WITH RECOVERY
GO
 
USE [CorruptionChallenge4]
 
SELECT * FROM dbo.Customers WHERE id IN (510900 ,510901)
-- alocation unit is not correct at page level
 
-- Allocation unit for the CIX in the table.
USE [CorruptionChallenge4]
 
SELECT au.allocation_unit_id,  * FROM sys.indexes AS ix
    INNER JOIN sys.partitions AS p
        ON p.object_id = ix.object_id
            AND p.index_id = ix.index_id
    INNER JOIN sys.allocation_units AS au
        ON au.container_id = p.hobt_id
WHERE ix.object_id = OBJECT_ID('dbo.Customers')
AND ix.index_id = 1
 
-- this bit is from Paul Randal PASS SUMMIT 2014 DEMO to modify the allocation unit
DECLARE @alloc BIGINT = 72057594039828480; -- Allocation unit recorded in metadata
DECLARE @index BIGINT;
SELECT @index =
    CONVERT (BIGINT,
        CONVERT (FLOAT, @alloc)
            * (1 / POWER (2.0, 48)) -- right shift, reciprocal of left shift
    );
SELECT
    CONVERT (BIGINT,
        CONVERT (FLOAT, @alloc - (@index * CONVERT (BIGINT, POWER (2.0, 48))))
            * (1 / POWER (2.0, 16)) -- right shift, reciprocal of left shift
    ) AS [m_objId],
    @index AS [m_indexId];
GO
--m_objId   m_indexId
--29    256
 
-- These numbers are in decimal
--replace with calculated values
 
-- Substitute those values on each data/index page
-- idobj at offset 24 for 4 bytes, idind at offset 6 for 2 bytes
 
-- Use a calculator to convert the numbers to hex, and then byte-reverse them
DBCC WRITEPAGE (N'CorruptionChallenge4', 3, 2150, 24, 4, 0x1D000000);
DBCC WRITEPAGE (N'CorruptionChallenge4', 3, 2150, 6, 2, 0x0001);
GO
 
-- After this I can see the data for those rows
USE [CorruptionChallenge4]
 
SELECT * FROM dbo.Customers WHERE id IN (510900 ,510901)
 
-- But we have to fix all pages... what about a loop?
-- Get all pages for the index
CREATE TABLE #dbccInd (
ID                  INT IDENTITY(1,1)
, PageFID           INT NULL
, PagePID           INT NULL
, IAMFID            INT NULL
, IAMPID            INT NULL
, ObjectID          INT NULL
, IndexID           INT NULL
, PartitionNumber   INT NULL
, PartitionID       BIGINT NULL
, iam_chain_type    SYSNAME NULL
, Pagetype          INT NULL
, IndexLevel        INT NULL
, NextPageFID       INT NULL
, NextPagePID       INT NULL
, PrevPageFID       INT NULL
, PrevPagePID       INT NULL
)
INSERT INTO #dbccInd
EXECUTE sp_executesql N'DBCC IND(''CorruptionChallenge4'', ''dbo.Customers'', 0)'
 
DECLARE @count  INT = 1
DECLARE @max    INT = (SELECT MAX(ID) FROM #dbccInd)
DECLARE @writepage  SYSNAME
DECLARE @pageNo INT
 
WHILE @count <= @max BEGIN
    SET @pageNo = (SELECT PagePID FROM #dbccInd WHERE ID = @count AND PageType = 1)
 
    IF @pageNo IS NULL BEGIN
        SET @count += 1
        CONTINUE
    END
 
    SET @writepage = N'DBCC WRITEPAGE (N''CorruptionChallenge4'', 3, ' + CONVERT(VARCHAR, @pageNo) + ', 24, 4, 0x1D000000)'
    EXECUTE sp_executesql @writepage
    SET @writepage = N'DBCC WRITEPAGE (N''CorruptionChallenge4'', 3, ' + CONVERT(VARCHAR, @pageNo) + ', 6, 2, 0x0001)'
    EXECUTE sp_executesql @writepage
 
    SET @count += 1
END
 
SELECT * FROM dbo.Customers
-- 511740
 
SELECT COUNT(*)
FROM sys.objects
WHERE is_ms_shipped = 0;
-- 5

 
Every data page in the [dbo].[customers] table was corrupt, and corrupt in the exact same way. Raul was able to loop through them all to correct the corruption.

There is is, that is how Raul completed the Database Corruption Challenge this week. Nice work Raul.

WARNING: DBCC WritePage is a dangerous command, that should never be used on any production database. It may invalidate your ability to get support from Microsoft on issues that arise with that database going forward. It is not my intention to encourage anyone to use DBCC WritePage ever. This is just what I used to create a corrupt database, and since creating corrupt databases is not part of the role of most DBAs, you should not use DBCC WritePage. Consider yourself warned.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.