[SQL][Script]救回被誤刪的資料

[SQL][Script]救回被誤刪的資料

在 SQL Server 下有時會發現資料不知道被誰刪除的,如果我們可以事先知道有刪除的動作,那麼透過 Audit 、SQL Trace 或者是 Trigger 等機制,那麼都還有辦法做紀錄。但如果事前沒有做這些處理,那麼該怎麼來處理呢 ? 前一陣子遇到類似的狀況,但客戶雖然用 ApexSQL Log 找回被刪除的資料,但對一值想不出來這個要怎麼做。昨天跟亂馬和 Terry 討論之後,感覺上透過 :fn_dblog 可以讀取 Log,雖然我們可以透過這個系統函數,可以把異動的動作 ( Action )和時間找出來,但資料呢 ? 看起來似乎要從紀錄中的 Binary 資料轉出來,但這方便似乎沒有相關資料說明。

 

透過亂馬客的協助和修正,他更改了一個版本的查看修改資料的命令。目前這個版本必須要在 Recovery Mode 是 Full 或者是 Bulk Insert 下來使用,測試起來如果是下 SQL 指令刪除資料的話 ( DELETE ),那麼透過這個 Stored Procedure,可以將被刪除的資料給找出來;但如果您的資料庫的 Recovery Mode 是 Simple 的狀況下,在還沒有發生 Checkpoint 之前,都還可以找到資料,但倘若發生 Checkpoint 的話,那麼就沒有機會了。

 

整個 Stored Procedure 有點複雜,中間有一大段都是 Binary 在轉碼處理,原作者的這一段有點小缺陷,並沒有辦法支援區分大小寫的資料庫,有些拼字要調整;另外針對有些時候,我們可能並不是直接下 SQL 指令刪除,可能會針對 ADO 的 Result Set 去操作,那麼他可能會把 SQL 指令變成 sp_executesql 'DELETE FROM …' 的指令,亂馬克也協助修正了這個問題,有興趣的朋友可以參考以下的程式碼。

   1:  
   2: -- http://raresql.com/2012/10/24/sql-server-how-to-find-who-deleted-what-records-at-what-time/
   3: -- Script Name: Recover_Deleted_Data_With_UID_Date_Time_Proc
   4: -- Script Type : Recovery Procedure 
   5: -- Develop By: Muhammad Imran
   6: -- Date Created: 24 Oct 2012
   7: -- Modify Date: 
   8: -- Version    : 1.2
   9: -- Notes      : 
  10: -- 1.修改不傳入DB Name改取自DB_NAME()
  11: -- 2.修改 sysname DataType to nvarchar(128)
  12: -- 3.使用SUSER_SNAME 代替 sysusers join 找出操作人員
  13: -- 4.修正在區分大小寫的DB中,會發生的錯誤
  14: -- 5.加入判斷,如下是透過SSMS的Edit Row時,刪除的[Transaction Name] 會用 user_transaction [Transaction Name] IN ('DELETE', 'user_transaction')
  15: -- Example: EXEC Recover_Deleted_Data_With_UID_Date_Time_Proc  'dbo.tbl_Sample'
  16: ALTER PROCEDURE Recover_Deleted_Data_With_UID_Date_Time_Proc
  17:     @SchemaName_n_TableName NVARCHAR(MAX) ,
  18:     @Date_From DATETIME = '1900/01/01' ,
  19:     @Date_To DATETIME = '9999/12/31'
  20: AS 
  21:     DECLARE @RowLogContents VARBINARY(8000)
  22:     DECLARE @TransactionID NVARCHAR(MAX)
  23:     DECLARE @AllocUnitID BIGINT
  24:     DECLARE @AllocUnitName NVARCHAR(MAX)
  25:     DECLARE @SQL NVARCHAR(MAX)
  26:     DECLARE @Compatibility_Level INT
  27:     DECLARE @Database_Name NVARCHAR(MAX    )
  28:  
  29:     SET @Database_Name = DB_NAME()
  30:     SELECT  @Compatibility_Level = dtb.compatibility_level
  31:     FROM    master.sys.databases AS dtb
  32:     WHERE   dtb.name = @Database_Name
  33:  
  34:     IF ISNULL(@Compatibility_Level, 0) <= 80 
  35:         BEGIN
  36:             RAISERROR('The compatibility level should be equal to or greater SQL SERVER 2005 (90)',16,1)
  37:             RETURN
  38:         END
  39:  
  40:     IF ( SELECT COUNT(*)
  41:          FROM   INFORMATION_SCHEMA.TABLES
  42:          WHERE  [TABLE_SCHEMA] + '.' + [TABLE_NAME] = @SchemaName_n_TableName
  43:        ) = 0 
  44:         BEGIN
  45:             RAISERROR('Could not found the table in the defined database',16,1)
  46:             RETURN
  47:         END
  48:  
  49:     DECLARE @bitTable TABLE
  50:         (
  51:           [ID] INT ,
  52:           [Bitvalue] INT
  53:         )
  54: --Create table to set the bit position of one byte.
  55:  
  56:     INSERT  INTO @bitTable
  57:             SELECT  0 ,
  58:                     2
  59:             UNION ALL
  60:             SELECT  1 ,
  61:                     2
  62:             UNION ALL
  63:             SELECT  2 ,
  64:                     4
  65:             UNION ALL
  66:             SELECT  3 ,
  67:                     8
  68:             UNION ALL
  69:             SELECT  4 ,
  70:                     16
  71:             UNION ALL
  72:             SELECT  5 ,
  73:                     32
  74:             UNION ALL
  75:             SELECT  6 ,
  76:                     64
  77:             UNION ALL
  78:             SELECT  7 ,
  79:                     128
  80:  
  81: --Create table to collect the row data.
  82:     DECLARE @DeletedRecords TABLE
  83:         (
  84:           [Row ID] INT IDENTITY(1, 1) ,
  85:           [RowLogContents] VARBINARY(8000) ,
  86:           [AllocUnitId] BIGINT ,
  87:           [Transaction ID] NVARCHAR(MAX) ,
  88:           [FixedLengthData] SMALLINT ,
  89:           [TotalNoOfCols] SMALLINT ,
  90:           [NullBitMapLength] SMALLINT ,
  91:           [NullBytes] VARBINARY(8000) ,
  92:           [TotalNoofVarCols] SMALLINT ,
  93:           [ColumnOffsetArray] VARBINARY(8000) ,
  94:           [VarColumnStart] SMALLINT ,
  95:           [Slot ID] INT ,
  96:           [NullBitMap] VARCHAR(MAX)
  97:         )
  98: --Create a common table expression to get all the row data plus how many bytes we have for each row.
  99: ;
 100:     WITH    RowData
 101:               AS ( SELECT   [RowLog Contents 0] AS [RowLogContents] ,
 102:                             [AllocUnitID] AS [AllocUnitID] ,
 103:                             [Transaction ID] AS [Transaction ID]  
 104:  
 105: --[Fixed Length Data] = Substring (RowLog content 0, Status Bit A+ Status Bit B + 1,2 bytes)
 106:                             ,
 107:                             CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 108:                                                               2 + 1, 2)))) AS [FixedLengthData]  --@FixedLengthData
 109:  
 110: -- [TotalnoOfCols] =  Substring (RowLog content 0, [Fixed Length Data] + 1,2 bytes)
 111:                             ,
 112:                             CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 113:                                                               CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 114:                                                               2 + 1, 2)))) + 1,
 115:                                                               2)))) AS [TotalNoOfCols]
 116:  
 117: --[NullBitMapLength]=ceiling([Total No of Columns] /8.0)
 118:                             ,
 119:                             CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 120:                                                               CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 121:                                                               2 + 1, 2)))) + 1,
 122:                                                               2)))) / 8.0)) AS [NullBitMapLength] 
 123:  
 124: --[Null Bytes] = Substring (RowLog content 0, Status Bit A+ Status Bit B + [Fixed Length Data] +1, [NullBitMapLength] )
 125:                             ,
 126:                             SUBSTRING([RowLog Contents 0],
 127:                                       CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 128:                                                               2 + 1, 2)))) + 3,
 129:                                       CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 130:                                                               CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 131:                                                               2 + 1, 2)))) + 1,
 132:                                                               2)))) / 8.0))) AS [NullBytes]
 133:  
 134: --[TotalNoofVarCols] = Substring (RowLog content 0, Status Bit A+ Status Bit B + [Fixed Length Data] +1, [Null Bitmap length] + 2 )
 135:                             ,
 136:                             ( CASE WHEN SUBSTRING([RowLog Contents 0], 1, 1) IN (
 137:                                         0x10, 0x30, 0x70 )
 138:                                    THEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 139:                                                               CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 140:                                                               2 + 1, 2)))) + 3
 141:                                                               + CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 142:                                                               CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 143:                                                               2 + 1, 2)))) + 1,
 144:                                                               2)))) / 8.0)), 2))))
 145:                                    ELSE NULL
 146:                               END ) AS [TotalNoofVarCols] 
 147:  
 148: --[ColumnOffsetArray]= Substring (RowLog content 0, Status Bit A+ Status Bit B + [Fixed Length Data] +1, [Null Bitmap length] + 2 , [TotalNoofVarCols]*2 )
 149:                             ,
 150:                             ( CASE WHEN SUBSTRING([RowLog Contents 0], 1, 1) IN (
 151:                                         0x10, 0x30, 0x70 )
 152:                                    THEN SUBSTRING([RowLog Contents 0],
 153:                                                   CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 154:                                                               2 + 1, 2)))) + 3
 155:                                                   + CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 156:                                                               CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 157:                                                               2 + 1, 2)))) + 1,
 158:                                                               2)))) / 8.0))
 159:                                                   + 2,
 160:                                                   ( CASE WHEN SUBSTRING([RowLog Contents 0],
 161:                                                               1, 1) IN ( 0x10,
 162:                                                               0x30, 0x70 )
 163:                                                          THEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 164:                                                               CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 165:                                                               2 + 1, 2)))) + 3
 166:                                                               + CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 167:                                                               CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 168:                                                               2 + 1, 2)))) + 1,
 169:                                                               2)))) / 8.0)), 2))))
 170:                                                          ELSE NULL
 171:                                                     END ) * 2)
 172:                                    ELSE NULL
 173:                               END ) AS [ColumnOffsetArray] 
 174:  
 175: --  Variable column Start = Status Bit A+ Status Bit B + [Fixed Length Data] + [Null Bitmap length] + 2+([TotalNoofVarCols]*2)
 176:                             ,
 177:                             CASE WHEN SUBSTRING([RowLog Contents 0], 1, 1) IN (
 178:                                       0x10, 0x30, 0x70 )
 179:                                  THEN ( CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 180:                                                               2 + 1, 2)))) + 4
 181:                                         + CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 182:                                                               CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 183:                                                               2 + 1, 2)))) + 1,
 184:                                                               2)))) / 8.0))
 185:                                         + ( ( CASE WHEN SUBSTRING([RowLog Contents 0],
 186:                                                               1, 1) IN ( 0x10,
 187:                                                               0x30, 0x70 )
 188:                                                    THEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 189:                                                               CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 190:                                                               2 + 1, 2)))) + 3
 191:                                                               + CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 192:                                                               CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
 193:                                                               2 + 1, 2)))) + 1,
 194:                                                               2)))) / 8.0)), 2))))
 195:                                                    ELSE NULL
 196:                                               END ) * 2 ) )
 197:                                  ELSE NULL
 198:                             END AS [VarColumnStart] ,
 199:                             [Slot ID]
 200:                    FROM     sys.fn_dblog(NULL, NULL)
 201:                    WHERE    AllocUnitId IN (
 202:                             SELECT  [Allocation_unit_id]
 203:                             FROM    sys.allocation_units allocunits
 204:                                     INNER JOIN sys.partitions partitions ON ( allocunits.type IN (
 205:                                                               1, 3 )
 206:                                                               AND partitions.hobt_id = allocunits.container_id
 207:                                                               )
 208:                                                               OR ( allocunits.type = 2
 209:                                                               AND partitions.partition_id = allocunits.container_id
 210:                                                               )
 211:                             WHERE   object_id = OBJECT_ID(''
 212:                                                           + @SchemaName_n_TableName
 213:                                                           + '') )
 214:                             AND Context IN ( 'LCX_MARK_AS_GHOST', 'LCX_HEAP' )
 215:                             AND Operation IN ( 'LOP_DELETE_ROWS' )
 216:                             AND SUBSTRING([RowLog Contents 0], 1, 1) IN ( 0x10,
 217:                                                               0x30, 0x70 )
 218:  
 219: /*Use this subquery to filter the date*/
 220:                             AND [TRANSACTION ID] IN (
 221:                             SELECT DISTINCT
 222:                                     [TRANSACTION ID]
 223:                             FROM    sys.fn_dblog(NULL, NULL)
 224:                             WHERE   Context IN ( 'LCX_NULL' )
 225:                                     AND Operation IN ( 'LOP_BEGIN_XACT' )
 226:                                     AND [Transaction Name] IN ('DELETE', 'user_transaction')                            
 227:                                     AND CONVERT(NVARCHAR(11), [Begin Time]) BETWEEN @Date_From
 228:                                                               AND
 229:                                                               @Date_To)
 230:                  ),
 231:  
 232: --Use this technique to repeate the row till the no of bytes of the row.
 233:             N1 ( n )
 234:               AS ( SELECT   1
 235:                    UNION ALL
 236:                    SELECT   1
 237:                  ),
 238:             N2 ( n )
 239:               AS ( SELECT   1
 240:                    FROM     N1 AS X ,
 241:                             N1 AS Y
 242:                  ),
 243:             N3 ( n )
 244:               AS ( SELECT   1
 245:                    FROM     N2 AS X ,
 246:                             N2 AS Y
 247:                  ),
 248:             N4 ( n )
 249:               AS ( SELECT   ROW_NUMBER() OVER ( ORDER BY X.n )
 250:                    FROM     N3 AS X ,
 251:                             N3 AS Y
 252:                  )
 253:         INSERT  INTO @DeletedRecords
 254:                 SELECT  RowLogContents ,
 255:                         [AllocUnitID] ,
 256:                         [Transaction ID] ,
 257:                         [FixedLengthData] ,
 258:                         [TotalNoOfCols] ,
 259:                         [NullBitMapLength] ,
 260:                         [NullBytes] ,
 261:                         [TotalNoofVarCols] ,
 262:                         [ColumnOffsetArray] ,
 263:                         [VarColumnStart] ,
 264:                         [Slot ID]
 265:          ---Get the Null value against each column (1 means null zero means not null)
 266:                         ,
 267:                         [NullBitMap] = ( REPLACE(STUFF(( SELECT
 268:                                                               ','
 269:                                                               + ( CASE
 270:                                                               WHEN [ID] = 0
 271:                                                               THEN CONVERT(NVARCHAR(1), ( SUBSTRING(NullBytes,
 272:                                                               n, 1) % 2 ))
 273:                                                               ELSE CONVERT(NVARCHAR(1), ( ( SUBSTRING(NullBytes,
 274:                                                               n, 1)
 275:                                                               / [Bitvalue] )
 276:                                                               % 2 ))
 277:                                                               END ) --as [NullBitMap]
 278:                                                          FROM N4 AS Nums
 279:                                                               JOIN RowData AS C ON n <= NullBitMapLength
 280:                                                               CROSS JOIN @bitTable
 281:                                                          WHERE
 282:                                                               C.[RowLogContents] = D.[RowLogContents]
 283:                                                          ORDER BY [RowLogContents] ,
 284:                                                               n ASC
 285:                                                        FOR
 286:                                                          XML PATH('')
 287:                                                        ), 1, 1, ''), ',', '') )
 288:                 FROM    RowData D
 289:  
 290:     IF ( SELECT COUNT(*)
 291:          FROM   @DeletedRecords
 292:        ) = 0 
 293:         BEGIN
 294:             RAISERROR('There is no data in the log as per the search criteria',16,1)
 295:             RETURN
 296:         END
 297:  
 298:     DECLARE @ColumnNameAndData TABLE
 299:         (
 300:           [Transaction ID] VARCHAR(100) ,
 301:           [Row ID] INT ,
 302:           [RowLogContents] VARBINARY(MAX) ,
 303:           [NAME] nvarchar(128) ,
 304:           [nullbit] SMALLINT ,
 305:           [leaf_offset] SMALLINT ,
 306:           [length] SMALLINT ,
 307:           [system_type_id] TINYINT ,
 308:           [bitpos] TINYINT ,
 309:           [xprec] TINYINT ,
 310:           [xscale] TINYINT ,
 311:           [is_null] INT ,
 312:           [Column value Size] INT ,
 313:           [Column Length] INT ,
 314:           [hex_Value] VARBINARY(MAX) ,
 315:           [Slot ID] INT ,
 316:           [Update] INT
 317:         )
 318:  
 319: --Create common table expression and join it with the rowdata table
 320: -- to get each column details
 321: /*This part is for variable data columns*/
 322: --@RowLogContents, 
 323: --(col.columnOffValue - col.columnLength) + 1,
 324: --col.columnLength
 325: --)
 326:     INSERT  INTO @ColumnNameAndData
 327:             SELECT  [Transaction ID] ,
 328:                     [Row ID] ,
 329:                     RowLogContents ,
 330:                     NAME ,
 331:                     cols.leaf_null_bit AS nullbit ,
 332:                     leaf_offset ,
 333:                     ISNULL(syscolumns.length, cols.max_length) AS [length] ,
 334:                     cols.system_type_id ,
 335:                     cols.leaf_bit_position AS bitpos ,
 336:                     ISNULL(syscolumns.xprec, cols.precision) AS xprec ,
 337:                     ISNULL(syscolumns.xscale, cols.scale) AS xscale ,
 338:                     SUBSTRING([NullBitMap], cols.leaf_null_bit, 1) AS is_null ,
 339:                     ( CASE WHEN leaf_offset < 1
 340:                                 AND SUBSTRING([NullBitMap], cols.leaf_null_bit,
 341:                                               1) = 0
 342:                            THEN ( CASE WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 343:                                                               ( 2
 344:                                                               * leaf_offset
 345:                                                               * -1 ) - 1, 2)))) > 30000
 346:                                        THEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 347:                                                               ( 2
 348:                                                               * leaf_offset
 349:                                                               * -1 ) - 1, 2))))
 350:                                             - POWER(2, 15)
 351:                                        ELSE CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 352:                                                               ( 2
 353:                                                               * leaf_offset
 354:                                                               * -1 ) - 1, 2))))
 355:                                   END )
 356:                       END ) AS [Column value Size] ,
 357:                     ( CASE WHEN leaf_offset < 1
 358:                                 AND SUBSTRING([NullBitMap], cols.leaf_null_bit,
 359:                                               1) = 0
 360:                            THEN ( CASE WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 361:                                                               ( 2
 362:                                                               * leaf_offset
 363:                                                               * -1 ) - 1, 2)))) > 30000
 364:                                             AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 365:                                                               ( 2
 366:                                                               * ( ( leaf_offset
 367:                                                               * -1 ) - 1 ) )
 368:                                                               - 1, 2)))), 0),
 369:                                                        [VarColumnStart]) < 30000
 370:                                        THEN ( CASE WHEN [system_type_id] IN (
 371:                                                         35, 34, 99 ) THEN 16
 372:                                                    ELSE 24
 373:                                               END )
 374:                                        WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 375:                                                               ( 2
 376:                                                               * leaf_offset
 377:                                                               * -1 ) - 1, 2)))) > 30000
 378:                                             AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 379:                                                               ( 2
 380:                                                               * ( ( leaf_offset
 381:                                                               * -1 ) - 1 ) )
 382:                                                               - 1, 2)))), 0),
 383:                                                        [VarColumnStart]) > 30000
 384:                                        THEN ( CASE WHEN [system_type_id] IN (
 385:                                                         35, 34, 99 ) THEN 16
 386:                                                    ELSE 24
 387:                                               END ) --24 
 388:                                        WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 389:                                                               ( 2
 390:                                                               * leaf_offset
 391:                                                               * -1 ) - 1, 2)))) < 30000
 392:                                             AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 393:                                                               ( 2
 394:                                                               * ( ( leaf_offset
 395:                                                               * -1 ) - 1 ) )
 396:                                                               - 1, 2)))), 0),
 397:                                                        [VarColumnStart]) < 30000
 398:                                        THEN ( CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 399:                                                               ( 2
 400:                                                               * leaf_offset
 401:                                                               * -1 ) - 1, 2))))
 402:                                               - ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 403:                                                               ( 2
 404:                                                               * ( ( leaf_offset
 405:                                                               * -1 ) - 1 ) )
 406:                                                               - 1, 2)))), 0),
 407:                                                        [VarColumnStart]) )
 408:                                        WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 409:                                                               ( 2
 410:                                                               * leaf_offset
 411:                                                               * -1 ) - 1, 2)))) < 30000
 412:                                             AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 413:                                                               ( 2
 414:                                                               * ( ( leaf_offset
 415:                                                               * -1 ) - 1 ) )
 416:                                                               - 1, 2)))), 0),
 417:                                                        [VarColumnStart]) > 30000
 418:                                        THEN POWER(2, 15)
 419:                                             + CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 420:                                                               ( 2
 421:                                                               * leaf_offset
 422:                                                               * -1 ) - 1, 2))))
 423:                                             - ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 424:                                                               ( 2
 425:                                                               * ( ( leaf_offset
 426:                                                               * -1 ) - 1 ) )
 427:                                                               - 1, 2)))), 0),
 428:                                                      [VarColumnStart])
 429:                                   END )
 430:                       END ) AS [Column Length] ,
 431:                     ( CASE WHEN SUBSTRING([NullBitMap], cols.leaf_null_bit, 1) = 1
 432:                            THEN NULL
 433:                            ELSE SUBSTRING(RowLogContents,
 434:                                           ( ( CASE WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 435:                                                               ( 2
 436:                                                               * leaf_offset
 437:                                                               * -1 ) - 1, 2)))) > 30000
 438:                                                    THEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 439:                                                               ( 2
 440:                                                               * leaf_offset
 441:                                                               * -1 ) - 1, 2))))
 442:                                                         - POWER(2, 15)
 443:                                                    ELSE CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 444:                                                               ( 2
 445:                                                               * leaf_offset
 446:                                                               * -1 ) - 1, 2))))
 447:                                               END )
 448:                                             - ( CASE WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 449:                                                               ( 2
 450:                                                               * leaf_offset
 451:                                                               * -1 ) - 1, 2)))) > 30000
 452:                                                           AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 453:                                                               ( 2
 454:                                                               * ( ( leaf_offset
 455:                                                               * -1 ) - 1 ) )
 456:                                                               - 1, 2)))), 0),
 457:                                                               [VarColumnStart]) < 30000
 458:                                                      THEN ( CASE
 459:                                                               WHEN [system_type_id] IN (
 460:                                                               35, 34, 99 )
 461:                                                               THEN 16
 462:                                                               ELSE 24
 463:                                                             END ) --24 
 464:                                                      WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 465:                                                               ( 2
 466:                                                               * leaf_offset
 467:                                                               * -1 ) - 1, 2)))) > 30000
 468:                                                           AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 469:                                                               ( 2
 470:                                                               * ( ( leaf_offset
 471:                                                               * -1 ) - 1 ) )
 472:                                                               - 1, 2)))), 0),
 473:                                                               [VarColumnStart]) > 30000
 474:                                                      THEN ( CASE
 475:                                                               WHEN [system_type_id] IN (
 476:                                                               35, 34, 99 )
 477:                                                               THEN 16
 478:                                                               ELSE 24
 479:                                                             END ) --24 
 480:                                                      WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 481:                                                               ( 2
 482:                                                               * leaf_offset
 483:                                                               * -1 ) - 1, 2)))) < 30000
 484:                                                           AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 485:                                                               ( 2
 486:                                                               * ( ( leaf_offset
 487:                                                               * -1 ) - 1 ) )
 488:                                                               - 1, 2)))), 0),
 489:                                                               [VarColumnStart]) < 30000
 490:                                                      THEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 491:                                                               ( 2
 492:                                                               * leaf_offset
 493:                                                               * -1 ) - 1, 2))))
 494:                                                           - ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 495:                                                               ( 2
 496:                                                               * ( ( leaf_offset
 497:                                                               * -1 ) - 1 ) )
 498:                                                               - 1, 2)))), 0),
 499:                                                               [VarColumnStart])
 500:                                                      WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 501:                                                               ( 2
 502:                                                               * leaf_offset
 503:                                                               * -1 ) - 1, 2)))) < 30000
 504:                                                           AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 505:                                                               ( 2
 506:                                                               * ( ( leaf_offset
 507:                                                               * -1 ) - 1 ) )
 508:                                                               - 1, 2)))), 0),
 509:                                                               [VarColumnStart]) > 30000
 510:                                                      THEN POWER(2, 15)
 511:                                                           + CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 512:                                                               ( 2
 513:                                                               * leaf_offset
 514:                                                               * -1 ) - 1, 2))))
 515:                                                           - ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 516:                                                               ( 2
 517:                                                               * ( ( leaf_offset
 518:                                                               * -1 ) - 1 ) )
 519:                                                               - 1, 2)))), 0),
 520:                                                               [VarColumnStart])
 521:                                                 END ) ) + 1,
 522:                                           ( CASE WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 523:                                                               ( 2
 524:                                                               * leaf_offset
 525:                                                               * -1 ) - 1, 2)))) > 30000
 526:                                                       AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 527:                                                               ( 2
 528:                                                               * ( ( leaf_offset
 529:                                                               * -1 ) - 1 ) )
 530:                                                               - 1, 2)))), 0),
 531:                                                               [VarColumnStart]) < 30000
 532:                                                  THEN ( CASE WHEN [system_type_id] IN (
 533:                                                               35, 34, 99 )
 534:                                                              THEN 16
 535:                                                              ELSE 24
 536:                                                         END ) --24 
 537:                                                  WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 538:                                                               ( 2
 539:                                                               * leaf_offset
 540:                                                               * -1 ) - 1, 2)))) > 30000
 541:                                                       AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 542:                                                               ( 2
 543:                                                               * ( ( leaf_offset
 544:                                                               * -1 ) - 1 ) )
 545:                                                               - 1, 2)))), 0),
 546:                                                               [VarColumnStart]) > 30000
 547:                                                  THEN ( CASE WHEN [system_type_id] IN (
 548:                                                               35, 34, 99 )
 549:                                                              THEN 16
 550:                                                              ELSE 24
 551:                                                         END ) --24 
 552:                                                  WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 553:                                                               ( 2
 554:                                                               * leaf_offset
 555:                                                               * -1 ) - 1, 2)))) < 30000
 556:                                                       AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 557:                                                               ( 2
 558:                                                               * ( ( leaf_offset
 559:                                                               * -1 ) - 1 ) )
 560:                                                               - 1, 2)))), 0),
 561:                                                               [VarColumnStart]) < 30000
 562:                                                  THEN ABS(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 563:                                                               ( 2
 564:                                                               * leaf_offset
 565:                                                               * -1 ) - 1, 2))))
 566:                                                           - ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 567:                                                               ( 2
 568:                                                               * ( ( leaf_offset
 569:                                                               * -1 ) - 1 ) )
 570:                                                               - 1, 2)))), 0),
 571:                                                               [VarColumnStart]))
 572:                                                  WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 573:                                                               ( 2
 574:                                                               * leaf_offset
 575:                                                               * -1 ) - 1, 2)))) < 30000
 576:                                                       AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 577:                                                               ( 2
 578:                                                               * ( ( leaf_offset
 579:                                                               * -1 ) - 1 ) )
 580:                                                               - 1, 2)))), 0),
 581:                                                               [VarColumnStart]) > 30000
 582:                                                  THEN POWER(2, 15)
 583:                                                       + CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 584:                                                               ( 2
 585:                                                               * leaf_offset
 586:                                                               * -1 ) - 1, 2))))
 587:                                                       - ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
 588:                                                               ( 2
 589:                                                               * ( ( leaf_offset
 590:                                                               * -1 ) - 1 ) )
 591:                                                               - 1, 2)))), 0),
 592:                                                               [VarColumnStart])
 593:                                             END ))
 594:                       END ) AS hex_Value ,
 595:                     [Slot ID] ,
 596:                     0
 597:             FROM    @DeletedRecords A
 598:                     INNER JOIN sys.allocation_units allocunits ON A.[AllocUnitId] = allocunits.[Allocation_Unit_Id]
 599:                     INNER JOIN sys.partitions partitions ON ( allocunits.type IN (
 600:                                                               1, 3 )
 601:                                                               AND partitions.hobt_id = allocunits.container_id
 602:                                                             )
 603:                                                             OR ( allocunits.type = 2
 604:                                                               AND partitions.partition_id = allocunits.container_id
 605:                                                               )
 606:                     INNER JOIN sys.system_internals_partition_columns cols ON cols.partition_id = partitions.partition_id
 607:                     LEFT OUTER JOIN syscolumns ON syscolumns.id = partitions.object_id
 608:                                                   AND syscolumns.colid = cols.partition_column_id
 609:             WHERE   leaf_offset < 0
 610:             UNION
 611: /*This part is for fixed data columns*/
 612:             SELECT  [Transaction ID] ,
 613:                     [Row ID] ,
 614:                     RowLogContents ,
 615:                     NAME ,
 616:                     cols.leaf_null_bit AS nullbit ,
 617:                     leaf_offset ,
 618:                     ISNULL(syscolumns.length, cols.max_length) AS [length] ,
 619:                     cols.system_type_id ,
 620:                     cols.leaf_bit_position AS bitpos ,
 621:                     ISNULL(syscolumns.xprec, cols.precision) AS xprec ,
 622:                     ISNULL(syscolumns.xscale, cols.scale) AS xscale ,
 623:                     SUBSTRING([NullBitMap], cols.leaf_null_bit, 1) AS is_null ,
 624:                     ( SELECT TOP 1
 625:                                 ISNULL(SUM(CASE WHEN C.leaf_offset > 1
 626:                                                 THEN max_length
 627:                                                 ELSE 0
 628:                                            END), 0)
 629:                       FROM      sys.system_internals_partition_columns C
 630:                       WHERE     cols.partition_id = C.partition_id
 631:                                 AND C.leaf_null_bit < cols.leaf_null_bit
 632:                     ) + 5 AS [Column value Size] ,
 633:                     syscolumns.length AS [Column Length] ,
 634:                     CASE WHEN SUBSTRING([NullBitMap], cols.leaf_null_bit, 1) = 1
 635:                          THEN NULL
 636:                          ELSE SUBSTRING(RowLogContents,
 637:                                         ( SELECT TOP 1
 638:                                                     ISNULL(SUM(CASE
 639:                                                               WHEN C.leaf_offset > 1
 640:                                                               AND C.leaf_bit_position = 0
 641:                                                               THEN max_length
 642:                                                               ELSE 0
 643:                                                               END), 0)
 644:                                           FROM      sys.system_internals_partition_columns C
 645:                                           WHERE     cols.partition_id = C.partition_id
 646:                                                     AND C.leaf_null_bit < cols.leaf_null_bit
 647:                                         ) + 5, syscolumns.length)
 648:                     END AS hex_Value ,
 649:                     [Slot ID] ,
 650:                     0
 651:             FROM    @DeletedRecords A
 652:                     INNER JOIN sys.allocation_units allocunits ON A.[AllocUnitId] = allocunits.[Allocation_Unit_Id]
 653:                     INNER JOIN sys.partitions partitions ON ( allocunits.type IN (
 654:                                                               1, 3 )
 655:                                                               AND partitions.hobt_id = allocunits.container_id
 656:                                                             )
 657:                                                             OR ( allocunits.type = 2
 658:                                                               AND partitions.partition_id = allocunits.container_id
 659:                                                               )
 660:                     INNER JOIN sys.system_internals_partition_columns cols ON cols.partition_id = partitions.partition_id
 661:                     LEFT OUTER JOIN syscolumns ON syscolumns.id = partitions.object_id
 662:                                                   AND syscolumns.colid = cols.partition_column_id
 663:             WHERE   leaf_offset > 0
 664:             ORDER BY nullbit
 665:  
 666:     DECLARE @BitColumnByte AS INT
 667:     SELECT  @BitColumnByte = CONVERT(INT, CEILING(COUNT(*) / 8.0))
 668:     FROM    @ColumnNameAndData
 669:     WHERE   [system_type_id] = 104;
 670:         WITH    N1 ( n )
 671:                   AS ( SELECT   1
 672:                        UNION ALL
 673:                        SELECT   1
 674:                      ),
 675:                 N2 ( n )
 676:                   AS ( SELECT   1
 677:                        FROM     N1 AS X ,
 678:                                 N1 AS Y
 679:                      ),
 680:                 N3 ( n )
 681:                   AS ( SELECT   1
 682:                        FROM     N2 AS X ,
 683:                                 N2 AS Y
 684:                      ),
 685:                 N4 ( n )
 686:                   AS ( SELECT   ROW_NUMBER() OVER ( ORDER BY X.n )
 687:                        FROM     N3 AS X ,
 688:                                 N3 AS Y
 689:                      ),
 690:                 CTE
 691:                   AS ( SELECT   RowLogContents ,
 692:                                 [nullbit] ,
 693:                                 [BitMap] = CONVERT(VARBINARY(1), CONVERT(INT, SUBSTRING(( REPLACE(STUFF(( SELECT
 694:                                                               ','
 695:                                                               + ( CASE
 696:                                                               WHEN [ID] = 0
 697:                                                               THEN CONVERT(NVARCHAR(1), ( SUBSTRING(hex_Value,
 698:                                                               n, 1) % 2 ))
 699:                                                               ELSE CONVERT(NVARCHAR(1), ( ( SUBSTRING(hex_Value,
 700:                                                               n, 1)
 701:                                                               / [Bitvalue] )
 702:                                                               % 2 ))
 703:                                                               END ) --as [NullBitMap]
 704:                                                               FROM
 705:                                                               N4 AS Nums
 706:                                                               JOIN @ColumnNameAndData
 707:                                                               AS C ON n <= @BitColumnByte
 708:                                                               AND [system_type_id] = 104
 709:                                                               AND bitpos = 0
 710:                                                               CROSS JOIN @bitTable
 711:                                                               WHERE
 712:                                                               C.[RowLogContents] = D.[RowLogContents]
 713:                                                               ORDER BY [RowLogContents] ,
 714:                                                               n ASC
 715:                                                               FOR
 716:                                                               XML
 717:                                                               PATH('')
 718:                                                               ), 1, 1, ''),
 719:                                                               ',', '') ),
 720:                                                               bitpos + 1, 1)))
 721:                        FROM     @ColumnNameAndData D
 722:                        WHERE    [system_type_id] = 104
 723:                      )
 724:         UPDATE  A
 725:         SET     [hex_Value] = [BitMap]
 726:         FROM    @ColumnNameAndData A
 727:                 INNER JOIN CTE B ON A.[RowLogContents] = B.[RowLogContents]
 728:                                     AND A.[nullbit] = B.[nullbit]
 729:  
 730:  
 731: /**************Check for BLOB DATA TYPES******************************/
 732:     DECLARE @Fileid INT
 733:     DECLARE @Pageid INT
 734:     DECLARE @Slotid INT
 735:     DECLARE @CurrentLSN INT
 736:     DECLARE @LinkID INT
 737:     DECLARE @Context VARCHAR(50)
 738:     DECLARE @ConsolidatedPageID VARCHAR(MAX)
 739:     DECLARE @LCX_TEXT_MIX VARBINARY(MAX)
 740:  
 741:     DECLARE @temppagedata TABLE
 742:         (
 743:           [ParentObject] nvarchar(128) ,
 744:           [Object] nvarchar(128) ,
 745:           [Field] nvarchar(128) ,
 746:           [Value] nvarchar(128)
 747:         )
 748:  
 749:     DECLARE @pagedata TABLE
 750:         (
 751:           [Page ID] nvarchar(128) ,
 752:           [FILE IDS] INT ,
 753:           [PAGE IDS] INT ,
 754:           [AllocUnitId] BIGINT ,
 755:           [ParentObject] nvarchar(128) ,
 756:           [Object] nvarchar(128) ,
 757:           [Field] nvarchar(128) ,
 758:           [Value] nvarchar(128)
 759:         )
 760:  
 761:     DECLARE @ModifiedRawData TABLE
 762:         (
 763:           [ID] INT IDENTITY(1, 1) ,
 764:           [PAGE ID] VARCHAR(MAX) ,
 765:           [FILE IDS] INT ,
 766:           [PAGE IDS] INT ,
 767:           [Slot ID] INT ,
 768:           [AllocUnitId] BIGINT ,
 769:           [RowLog Contents 0_var] VARCHAR(MAX) ,
 770:           [RowLog Length] VARCHAR(50) ,
 771:           [RowLog Len] INT ,
 772:           [RowLog Contents 0] VARBINARY(MAX) ,
 773:           [LINK ID] INT DEFAULT ( 0 ) ,
 774:           [Update] INT
 775:         )
 776:  
 777:     DECLARE Page_Data_Cursor CURSOR
 778:     FOR
 779:         /*We need to filter LOP_MODIFY_ROW,LOP_MODIFY_COLUMNS from log for deleted records of BLOB data type& Get its Slot No, Page ID & AllocUnit ID*/
 780:             SELECT  LTRIM(RTRIM(REPLACE([Description], 'Deallocated', ''))) AS [PAGE ID] ,
 781:                     [Slot ID] ,
 782:                     [AllocUnitId] ,
 783:                     NULL AS [RowLog Contents 0] ,
 784:                     NULL AS [RowLog Contents 0] ,
 785:                     Context
 786:             FROM    sys.fn_dblog(NULL, NULL)
 787:             WHERE   AllocUnitId IN (
 788:                     SELECT  [Allocation_unit_id]
 789:                     FROM    sys.allocation_units allocunits
 790:                             INNER JOIN sys.partitions partitions ON ( allocunits.type IN (
 791:                                                               1, 3 )
 792:                                                               AND partitions.hobt_id = allocunits.container_id
 793:                                                               )
 794:                                                               OR ( allocunits.type = 2
 795:                                                               AND partitions.partition_id = allocunits.container_id
 796:                                                               )
 797:                     WHERE   object_id = OBJECT_ID('' + @SchemaName_n_TableName
 798:                                                   + '') )
 799:                     AND Operation IN ( 'LOP_MODIFY_ROW' )
 800:                     AND [Context] IN ( 'LCX_PFS' )
 801:                     AND Description LIKE '%Deallocated%'
 802:             /*Use this subquery to filter the date*/
 803:                     AND [TRANSACTION ID] IN (
 804:                     SELECT DISTINCT
 805:                             [TRANSACTION ID]
 806:                     FROM    sys.fn_dblog(NULL, NULL)
 807:                     WHERE   Context IN ( 'LCX_NULL' )
 808:                             AND Operation IN ( 'LOP_BEGIN_XACT' )
 809:                             AND [Transaction Name] IN ('DELETE', 'user_transaction')
 810:                             AND CONVERT(NVARCHAR(11), [Begin Time]) BETWEEN @Date_From
 811:                                                               AND
 812:                                                               @Date_To )
 813:             GROUP BY [Description] ,
 814:                     [Slot ID] ,
 815:                     [AllocUnitId] ,
 816:                     Context
 817:             UNION
 818:             SELECT  [PAGE ID] ,
 819:                     [Slot ID] ,
 820:                     [AllocUnitId] ,
 821:                     SUBSTRING([RowLog Contents 0], 15,
 822:                               LEN([RowLog Contents 0])) AS [RowLog Contents 0] ,
 823:                     CONVERT(INT, SUBSTRING([RowLog Contents 0], 7, 2)) ,
 824:                     Context --,CAST(RIGHT([Current LSN],4) AS INT) AS [Current LSN]
 825:             FROM    sys.fn_dblog(NULL, NULL)
 826:             WHERE   AllocUnitId IN (
 827:                     SELECT  [Allocation_unit_id]
 828:                     FROM    sys.allocation_units allocunits
 829:                             INNER JOIN sys.partitions partitions ON ( allocunits.type IN (
 830:                                                               1, 3 )
 831:                                                               AND partitions.hobt_id = allocunits.container_id
 832:                                                               )
 833:                                                               OR ( allocunits.type = 2
 834:                                                               AND partitions.partition_id = allocunits.container_id
 835:                                                               )
 836:                     WHERE   object_id = OBJECT_ID('' + @SchemaName_n_TableName
 837:                                                   + '') )
 838:                     AND Context IN ( 'LCX_TEXT_MIX' )
 839:                     AND Operation IN ( 'LOP_DELETE_ROWS' ) 
 840:             /*Use this subquery to filter the date*/
 841:                     AND [TRANSACTION ID] IN (
 842:                     SELECT DISTINCT
 843:                             [TRANSACTION ID]
 844:                     FROM    sys.fn_dblog(NULL, NULL)
 845:                     WHERE   Context IN ( 'LCX_NULL' )
 846:                             AND Operation IN ( 'LOP_BEGIN_XACT' )
 847:                             AND [Transaction Name] IN ('DELETE', 'user_transaction')
 848:                             AND CONVERT(NVARCHAR(11), [Begin Time]) BETWEEN @Date_From
 849:                                                               AND
 850:                                                               @Date_To )
 851:                          
 852:             /****************************************/
 853:  
 854:     OPEN Page_Data_Cursor
 855:  
 856:     FETCH NEXT FROM Page_Data_Cursor INTO @ConsolidatedPageID, @Slotid,
 857:         @AllocUnitID, @LCX_TEXT_MIX, @LinkID, @Context
 858:  
 859:     WHILE @@FETCH_STATUS = 0 
 860:         BEGIN
 861:             DECLARE @hex_pageid AS VARCHAR(MAX)
 862:             /*Page ID contains File Number and page number It looks like 0001:00000130.
 863:               In this example 0001 is file Number &  00000130 is Page Number & These numbers are in Hex format*/
 864:             SET @Fileid = SUBSTRING(@ConsolidatedPageID, 0,
 865:                                     CHARINDEX(':', @ConsolidatedPageID)) -- Seperate File ID from Page ID
 866:          
 867:             SET @hex_pageid = '0x' + SUBSTRING(@ConsolidatedPageID,
 868:                                                CHARINDEX(':',
 869:                                                          @ConsolidatedPageID)
 870:                                                + 1, LEN(@ConsolidatedPageID))  ---Seperate the page ID
 871:             SELECT  @Pageid = CONVERT(INT, CAST('' AS XML).value('xs:hexBinary(substring(sql:variable("@hex_pageid"),sql:column("t.pos")) )',
 872:                                                               'varbinary(max)')) -- Convert Page ID from hex to integer
 873:             FROM    ( SELECT    CASE SUBSTRING(@hex_pageid, 1, 2)
 874:                                   WHEN '0x' THEN 3
 875:                                   ELSE 0
 876:                                 END
 877:                     ) AS t ( pos ) 
 878:              
 879:             IF @Context = 'LCX_PFS' 
 880:                 BEGIN
 881:                     DELETE  @temppagedata
 882:                     INSERT  INTO @temppagedata
 883:                             EXEC
 884:                                 ( 'DBCC PAGE(' + @Database_Name + ', '
 885:                                   + @Fileid + ', ' + @Pageid
 886:                                   + ', 1) with tableresults,no_infomsgs;'
 887:                                 ); 
 888:                     INSERT  INTO @pagedata
 889:                             SELECT  @ConsolidatedPageID ,
 890:                                     @Fileid ,
 891:                                     @Pageid ,
 892:                                     @AllocUnitID ,
 893:                                     [ParentObject] ,
 894:                                     [Object] ,
 895:                                     [Field] ,
 896:                                     [Value]
 897:                             FROM    @temppagedata
 898:                 END
 899:             ELSE 
 900:                 IF @Context = 'LCX_TEXT_MIX' 
 901:                     BEGIN
 902:                         INSERT  INTO @ModifiedRawData
 903:                                 SELECT  @ConsolidatedPageID ,
 904:                                         @Fileid ,
 905:                                         @Pageid ,
 906:                                         @Slotid ,
 907:                                         @AllocUnitID ,
 908:                                         NULL ,
 909:                                         0 ,
 910:                                         CONVERT(INT, CONVERT(VARBINARY, REVERSE(SUBSTRING(@LCX_TEXT_MIX,
 911:                                                               11, 2)))) ,
 912:                                         @LCX_TEXT_MIX ,
 913:                                         @LinkID ,
 914:                                         0
 915:                     END    
 916:             FETCH NEXT FROM Page_Data_Cursor INTO @ConsolidatedPageID, @Slotid,
 917:                 @AllocUnitID, @LCX_TEXT_MIX, @LinkID, @Context
 918:         END
 919:      
 920:     CLOSE Page_Data_Cursor
 921:     DEALLOCATE Page_Data_Cursor
 922:  
 923:     DECLARE @Newhexstring VARCHAR(MAX);
 924:  
 925:     --The data is in multiple rows in the page, so we need to convert it into one row as a single hex value.
 926:     --This hex value is in string format
 927:     INSERT  INTO @ModifiedRawData
 928:             ( [PAGE ID] ,
 929:               [FILE IDS] ,
 930:               [PAGE IDS] ,
 931:               [Slot ID] ,
 932:               [AllocUnitId] ,
 933:               [RowLog Contents 0_var] ,
 934:               [RowLog Length]
 935:             )
 936:             SELECT  [Page ID] ,
 937:                     [FILE IDS] ,
 938:                     [PAGE IDS] ,
 939:                     SUBSTRING([ParentObject],
 940:                               CHARINDEX('Slot', [ParentObject]) + 4,
 941:                               ( CHARINDEX('Offset', [ParentObject])
 942:                                 - ( CHARINDEX('Slot', [ParentObject]) + 4 ) )
 943:                               - 2) AS [Slot ID] ,
 944:                     [AllocUnitId] ,
 945:                     SUBSTRING(( SELECT  REPLACE(STUFF(( SELECT
 946:                                                               REPLACE(SUBSTRING([Value],
 947:                                                               CHARINDEX(':',
 948:                                                               [Value]) + 1,
 949:                                                               CHARINDEX('†',
 950:                                                               [Value])
 951:                                                               - CHARINDEX(':',
 952:                                                               [Value])), '†',
 953:                                                               '')
 954:                                                         FROM  @pagedata C
 955:                                                         WHERE B.[Page ID] = C.[Page ID]
 956:                                                               AND SUBSTRING(B.[ParentObject],
 957:                                                               CHARINDEX('Slot',
 958:                                                               B.[ParentObject])
 959:                                                               + 4,
 960:                                                               ( CHARINDEX('Offset',
 961:                                                               B.[ParentObject])
 962:                                                               - ( CHARINDEX('Slot',
 963:                                                               B.[ParentObject])
 964:                                                               + 4 ) )) = SUBSTRING(C.[ParentObject],
 965:                                                               CHARINDEX('Slot',
 966:                                                               C.[ParentObject])
 967:                                                               + 4,
 968:                                                               ( CHARINDEX('Offset',
 969:                                                               C.[ParentObject])
 970:                                                               - ( CHARINDEX('Slot',
 971:                                                               C.[ParentObject])
 972:                                                               + 4 ) ))
 973:                                                               AND [Object] LIKE '%Memory Dump%'
 974:                                                         ORDER BY '0x'
 975:                                                               + LEFT([Value],
 976:                                                               CHARINDEX(':',
 977:                                                               [Value]) - 1)
 978:                                                       FOR
 979:                                                         XML PATH('')
 980:                                                       ), 1, 1, ''), ' ', '')
 981:                               ), 1, 20000) AS [Value] ,
 982:                     SUBSTRING(( SELECT  '0x'
 983:                                         + REPLACE(STUFF(( SELECT
 984:                                                               REPLACE(SUBSTRING([Value],
 985:                                                               CHARINDEX(':',
 986:                                                               [Value]) + 1,
 987:                                                               CHARINDEX('†',
 988:                                                               [Value])
 989:                                                               - CHARINDEX(':',
 990:                                                               [Value])), '†',
 991:                                                               '')
 992:                                                           FROM
 993:                                                               @pagedata C
 994:                                                           WHERE
 995:                                                               B.[Page ID] = C.[Page ID]
 996:                                                               AND SUBSTRING(B.[ParentObject],
 997:                                                               CHARINDEX('Slot',
 998:                                                               B.[ParentObject])
 999:                                                               + 4,
1000:                                                               ( CHARINDEX('Offset',
1001:                                                               B.[ParentObject])
1002:                                                               - ( CHARINDEX('Slot',
1003:                                                               B.[ParentObject])
1004:                                                               + 4 ) )) = SUBSTRING(C.[ParentObject],
1005:                                                               CHARINDEX('Slot',
1006:                                                               C.[ParentObject])
1007:                                                               + 4,
1008:                                                               ( CHARINDEX('Offset',
1009:                                                               C.[ParentObject])
1010:                                                               - ( CHARINDEX('Slot',
1011:                                                               C.[ParentObject])
1012:                                                               + 4 ) ))
1013:                                                               AND [Object] LIKE '%Memory Dump%'
1014:                                                           ORDER BY '0x'
1015:                                                               + LEFT([Value],
1016:                                                               CHARINDEX(':',
1017:                                                               [Value]) - 1)
1018:                                                         FOR
1019:                                                           XML PATH('')
1020:                                                         ), 1, 1, ''), ' ', '')
1021:                               ), 7, 4) AS [Length]
1022:             FROM    @pagedata B
1023:             WHERE   [Object] LIKE '%Memory Dump%'
1024:             GROUP BY [Page ID] ,
1025:                     [FILE IDS] ,
1026:                     [PAGE IDS] ,
1027:                     [ParentObject] ,
1028:                     [AllocUnitId]--,[Current LSN]
1029:             ORDER BY [Slot ID]
1030:  
1031:     UPDATE  @ModifiedRawData
1032:     SET     [RowLog Len] = CONVERT(VARBINARY(8000), REVERSE(CAST('' AS XML).value('xs:hexBinary(substring(sql:column("[RowLog Length]"),0))',
1033:                                                               'varbinary(Max)')))
1034:     FROM    @ModifiedRawData
1035:     WHERE   [LINK ID] = 0
1036:  
1037:     UPDATE  @ModifiedRawData
1038:     SET     [RowLog Contents 0] = CAST('' AS XML).value('xs:hexBinary(substring(sql:column("[RowLog Contents 0_var]"),0))',
1039:                                                         'varbinary(Max)')
1040:     FROM    @ModifiedRawData
1041:     WHERE   [LINK ID] = 0
1042:  
1043:     UPDATE  B
1044:     SET     B.[RowLog Contents 0] = ( CASE WHEN A.[RowLog Contents 0] IS NOT NULL
1045:                                                 AND C.[RowLog Contents 0] IS NOT NULL
1046:                                            THEN A.[RowLog Contents 0]
1047:                                                 + C.[RowLog Contents 0]
1048:                                            WHEN A.[RowLog Contents 0] IS NULL
1049:                                                 AND C.[RowLog Contents 0] IS NOT NULL
1050:                                            THEN C.[RowLog Contents 0]
1051:                                            WHEN A.[RowLog Contents 0] IS NOT NULL
1052:                                                 AND C.[RowLog Contents 0] IS NULL
1053:                                            THEN A.[RowLog Contents 0]
1054:                                       END ) ,
1055:             B.[Update] = ISNULL(B.[Update], 0) + 1
1056:     FROM    @ModifiedRawData B
1057:             LEFT JOIN @ModifiedRawData A ON A.[PAGE IDS] = CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
1058:                                                               15 + 14, 2))))
1059:                                             AND A.[FILE IDS] = CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
1060:                                                               19 + 14, 2))))
1061:                                             AND A.[LINK ID] = B.[LINK ID]
1062:             LEFT JOIN @ModifiedRawData C ON C.[PAGE IDS] = CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
1063:                                                               27 + 14, 2))))
1064:                                             AND C.[FILE IDS] = CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
1065:                                                               31 + 14, 2))))
1066:                                             AND C.[LINK ID] = B.[LINK ID]
1067:     WHERE   ( A.[RowLog Contents 0] IS NOT NULL
1068:               OR C.[RowLog Contents 0] IS NOT NULL
1069:             )
1070:  
1071:  
1072:     UPDATE  B
1073:     SET     B.[RowLog Contents 0] = ( CASE WHEN A.[RowLog Contents 0] IS NOT NULL
1074:                                                 AND C.[RowLog Contents 0] IS NOT NULL
1075:                                            THEN A.[RowLog Contents 0]
1076:                                                 + C.[RowLog Contents 0]
1077:                                            WHEN A.[RowLog Contents 0] IS NULL
1078:                                                 AND C.[RowLog Contents 0] IS NOT NULL
1079:                                            THEN C.[RowLog Contents 0]
1080:                                            WHEN A.[RowLog Contents 0] IS NOT NULL
1081:                                                 AND C.[RowLog Contents 0] IS NULL
1082:                                            THEN A.[RowLog Contents 0]
1083:                                       END )
1084:     --,B.[Update]=ISNULL(B.[Update],0)+1
1085:     FROM    @ModifiedRawData B
1086:             LEFT JOIN @ModifiedRawData A ON A.[PAGE IDS] = CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
1087:                                                               15 + 14, 2))))
1088:                                             AND A.[FILE IDS] = CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
1089:                                                               19 + 14, 2))))
1090:                                             AND A.[LINK ID] <> B.[LINK ID]
1091:                                             AND B.[Update] = 0
1092:             LEFT JOIN @ModifiedRawData C ON C.[PAGE IDS] = CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
1093:                                                               27 + 14, 2))))
1094:                                             AND C.[FILE IDS] = CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
1095:                                                               31 + 14, 2))))
1096:                                             AND C.[LINK ID] <> B.[LINK ID]
1097:                                             AND B.[Update] = 0
1098:     WHERE   ( A.[RowLog Contents 0] IS NOT NULL
1099:               OR C.[RowLog Contents 0] IS NOT NULL
1100:             )
1101:  
1102:     UPDATE  @ModifiedRawData
1103:     SET     [RowLog Contents 0] = ( CASE WHEN [RowLog Len] >= 8000
1104:                                          THEN SUBSTRING([RowLog Contents 0],
1105:                                                         15, [RowLog Len])
1106:                                          WHEN [RowLog Len] < 8000
1107:                                          THEN SUBSTRING([RowLog Contents 0],
1108:                                                         15 + 6,
1109:                                                         CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([RowLog Contents 0],
1110:                                                               15, 6)))))
1111:                                     END )
1112:     FROM    @ModifiedRawData
1113:     WHERE   [LINK ID] = 0
1114:  
1115:     UPDATE  @ColumnNameAndData
1116:     SET     [hex_Value] = [RowLog Contents 0] 
1117:     --,A.[Update]=A.[Update]+1
1118:     FROM    @ColumnNameAndData A
1119:             INNER JOIN @ModifiedRawData B ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_Value],
1120:                                                               17, 4)))) = [PAGE IDS]
1121:                                              AND CONVERT(INT, SUBSTRING([hex_Value],
1122:                                                               9, 2)) = B.[LINK ID]
1123:     WHERE   [system_type_id] IN ( 99, 167, 175, 231, 239, 241, 165, 98 )
1124:             AND [LINK ID] <> 0 
1125:  
1126:     UPDATE  @ColumnNameAndData
1127:     SET     [hex_Value] = ( CASE WHEN B.[RowLog Contents 0] IS NOT NULL
1128:                                       AND C.[RowLog Contents 0] IS NOT NULL
1129:                                  THEN B.[RowLog Contents 0]
1130:                                       + C.[RowLog Contents 0]
1131:                                  WHEN B.[RowLog Contents 0] IS NULL
1132:                                       AND C.[RowLog Contents 0] IS NOT NULL
1133:                                  THEN C.[RowLog Contents 0]
1134:                                  WHEN B.[RowLog Contents 0] IS NOT NULL
1135:                                       AND C.[RowLog Contents 0] IS NULL
1136:                                  THEN B.[RowLog Contents 0]
1137:                             END )
1138:     --,A.[Update]=A.[Update]+1
1139:     FROM    @ColumnNameAndData A
1140:             LEFT JOIN @ModifiedRawData B ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_Value],
1141:                                                               5, 4)))) = B.[PAGE IDS]
1142:                                             AND B.[LINK ID] = 0
1143:             LEFT JOIN @ModifiedRawData C ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_Value],
1144:                                                               17, 4)))) = C.[PAGE IDS]
1145:                                             AND C.[LINK ID] = 0
1146:     WHERE   [system_type_id] IN ( 99, 167, 175, 231, 239, 241, 165, 98 )
1147:             AND ( B.[RowLog Contents 0] IS NOT NULL
1148:                   OR C.[RowLog Contents 0] IS NOT NULL
1149:                 )
1150:  
1151:     UPDATE  @ColumnNameAndData
1152:     SET     [hex_Value] = [RowLog Contents 0] 
1153:     --,A.[Update]=A.[Update]+1
1154:     FROM    @ColumnNameAndData A
1155:             INNER JOIN @ModifiedRawData B ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_Value],
1156:                                                               9, 4)))) = [PAGE IDS]
1157:                                              AND CONVERT(INT, SUBSTRING([hex_Value],
1158:                                                               3, 2)) = [LINK ID]
1159:     WHERE   [system_type_id] IN ( 35, 34, 99 )
1160:             AND [LINK ID] <> 0 
1161:      
1162:     UPDATE  @ColumnNameAndData
1163:     SET     [hex_Value] = [RowLog Contents 0]
1164:     --,A.[Update]=A.[Update]+10
1165:     FROM    @ColumnNameAndData A
1166:             INNER JOIN @ModifiedRawData B ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_Value],
1167:                                                               9, 4)))) = [PAGE IDS]
1168:     WHERE   [system_type_id] IN ( 35, 34, 99 )
1169:             AND [LINK ID] = 0
1170:  
1171:     UPDATE  @ColumnNameAndData
1172:     SET     [hex_Value] = [RowLog Contents 0] 
1173:     --,A.[Update]=A.[Update]+1
1174:     FROM    @ColumnNameAndData A
1175:             INNER JOIN @ModifiedRawData B ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_Value],
1176:                                                               15, 4)))) = [PAGE IDS]
1177:     WHERE   [system_type_id] IN ( 35, 34, 99 )
1178:             AND [LINK ID] = 0
1179:  
1180:     UPDATE  @ColumnNameAndData
1181:     SET     [hex_Value] = 0xFFFE + SUBSTRING([hex_Value], 9, LEN([hex_Value]))
1182:     --,[Update]=[Update]+1
1183:     WHERE   [system_type_id] = 241
1184:  
1185:     CREATE TABLE [#temp_Data]
1186:         (
1187:           [FieldName] VARCHAR(MAX) ,
1188:           [FieldValue] NVARCHAR(MAX) ,
1189:           [RowLogContents] VARBINARY(8000) ,
1190:           [Row ID] INT ,
1191:           [Transaction ID] VARCHAR(100) ,
1192:           [Deletion Date Time] DATETIME ,
1193:           [Deleted By User Name] VARCHAR(MAX)
1194:         )
1195:  
1196:     INSERT  INTO #temp_Data
1197:             SELECT  NAME ,
1198:                     CASE WHEN system_type_id IN ( 231, 239 )
1199:                          THEN LTRIM(RTRIM(CONVERT(NVARCHAR(MAX), hex_Value)))  --NVARCHAR ,NCHAR
1200:                          WHEN system_type_id IN ( 167, 175 )
1201:                          THEN LTRIM(RTRIM(CONVERT(VARCHAR(MAX), hex_Value)))  --VARCHAR,CHAR
1202:                          WHEN system_type_id IN ( 35 )
1203:                          THEN LTRIM(RTRIM(CONVERT(VARCHAR(MAX), hex_Value))) --Text
1204:                          WHEN system_type_id IN ( 99 )
1205:                          THEN LTRIM(RTRIM(CONVERT(NVARCHAR(MAX), hex_Value))) --nText 
1206:                          WHEN system_type_id = 48
1207:                          THEN CONVERT(VARCHAR(MAX), CONVERT(TINYINT, CONVERT(BINARY(1), REVERSE(hex_Value)))) --TINY INTEGER
1208:                          WHEN system_type_id = 52
1209:                          THEN CONVERT(VARCHAR(MAX), CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(hex_Value)))) --SMALL INTEGER
1210:                          WHEN system_type_id = 56
1211:                          THEN CONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(4), REVERSE(hex_Value)))) -- INTEGER
1212:                          WHEN system_type_id = 127
1213:                          THEN CONVERT(VARCHAR(MAX), CONVERT(BIGINT, CONVERT(BINARY(8), REVERSE(hex_Value))))-- BIG INTEGER
1214:                          WHEN system_type_id = 61
1215:                          THEN CONVERT(VARCHAR(MAX), CONVERT(DATETIME, CONVERT(VARBINARY(8000), REVERSE(hex_Value))), 100) --DATETIME
1216:                          WHEN system_type_id = 58
1217:                          THEN CONVERT(VARCHAR(MAX), CONVERT(SMALLDATETIME, CONVERT(VARBINARY(8000), REVERSE(hex_Value))), 100) --SMALL DATETIME
1218:                          WHEN system_type_id = 108
1219:                          THEN CONVERT(VARCHAR(MAX), CONVERT(NUMERIC(38, 20), CONVERT(VARBINARY, CONVERT(VARBINARY(1), xprec)
1220:                               + CONVERT(VARBINARY(1), xscale))
1221:                               + CONVERT(VARBINARY(1), 0) + hex_Value)) --- NUMERIC
1222:                          WHEN system_type_id = 106
1223:                          THEN CONVERT(VARCHAR(MAX), CONVERT(DECIMAL(38, 20), CONVERT(VARBINARY, CONVERT(VARBINARY(1), xprec)
1224:                               + CONVERT(VARBINARY(1), xscale))
1225:                               + CONVERT(VARBINARY(1), 0) + hex_Value)) --- DECIMAL
1226:                          WHEN system_type_id IN ( 60, 122 )
1227:                          THEN CONVERT(VARCHAR(MAX), CONVERT(MONEY, CONVERT(VARBINARY(8000), REVERSE(hex_Value))), 2) --MONEY,SMALLMONEY
1228:                          WHEN system_type_id = 104
1229:                          THEN CONVERT(VARCHAR(MAX), CONVERT (BIT, CONVERT(BINARY(1), hex_Value)
1230:                               % 2))  -- BIT
1231:                          WHEN system_type_id = 62
1232:                          THEN RTRIM(LTRIM(STR(CONVERT(FLOAT, SIGN(CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) AS BIGINT))
1233:                                               * ( 1.0
1234:                                                   + ( CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) AS BIGINT)
1235:                                                       & 0x000FFFFFFFFFFFFF )
1236:                                                   * POWER(CAST(2 AS FLOAT),
1237:                                                           -52) )
1238:                                               * POWER(CAST(2 AS FLOAT),
1239:                                                       ( ( CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) AS BIGINT)
1240:                                                           & 0x7ff0000000000000 )
1241:                                                         / EXP(52 * LOG(2))
1242:                                                         - 1023 ))), 53,
1243:                                               LEN(hex_Value)))) --- FLOAT
1244:                          WHEN system_type_id = 59
1245:                          THEN LEFT(LTRIM(STR(CAST(SIGN(CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) AS BIGINT))
1246:                                              * ( 1.0
1247:                                                  + ( CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) AS BIGINT)
1248:                                                      & 0x007FFFFF )
1249:                                                  * POWER(CAST(2 AS REAL), -23) )
1250:                                              * POWER(CAST(2 AS REAL),
1251:                                                      ( ( ( CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) AS INT) )
1252:                                                          & 0x7f800000 )
1253:                                                        / EXP(23 * LOG(2))
1254:                                                        - 127 )) AS REAL), 23,
1255:                                              23)), 8) --Real
1256:                          WHEN system_type_id IN ( 165, 173 )
1257:                          THEN ( CASE WHEN CHARINDEX(0x,
1258:                                                     CAST('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
1259:                                                               'VARBINARY(8000)')) = 0
1260:                                      THEN '0x'
1261:                                      ELSE ''
1262:                                 END ) + CAST('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
1263:                                                               'varchar(max)') -- BINARY,VARBINARY
1264:                          WHEN system_type_id = 34
1265:                          THEN ( CASE WHEN CHARINDEX(0x,
1266:                                                     CAST('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
1267:                                                               'VARBINARY(8000)')) = 0
1268:                                      THEN '0x'
1269:                                      ELSE ''
1270:                                 END ) + CAST('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
1271:                                                               'varchar(max)')  --IMAGE
1272:                          WHEN system_type_id = 36
1273:                          THEN CONVERT(VARCHAR(MAX), CONVERT(UNIQUEIDENTIFIER, hex_Value)) --UNIQUEIDENTIFIER
1274:                          WHEN system_type_id = 231
1275:                          THEN CONVERT(VARCHAR(MAX), CONVERT(nvarchar(128), hex_Value)) --nvarchar(128)
1276:                          WHEN system_type_id = 241
1277:                          THEN CONVERT(VARCHAR(MAX), CONVERT(XML, hex_Value)) --XML
1278:                          WHEN system_type_id = 189
1279:                          THEN ( CASE WHEN CHARINDEX(0x,
1280:                                                     CAST('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
1281:                                                               'VARBINARY(8000)')) = 0
1282:                                      THEN '0x'
1283:                                      ELSE ''
1284:                                 END ) + CAST('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
1285:                                                               'varchar(max)') --TIMESTAMP
1286:                          WHEN system_type_id = 98
1287:                          THEN ( CASE WHEN CONVERT(INT, SUBSTRING(hex_Value, 1,
1288:                                                               1)) = 56
1289:                                      THEN CONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(4), REVERSE(SUBSTRING(hex_Value,
1290:                                                               3,
1291:                                                               LEN(hex_Value))))))  -- INTEGER
1292:                                      WHEN CONVERT(INT, SUBSTRING(hex_Value, 1,
1293:                                                               1)) = 108
1294:                                      THEN CONVERT(VARCHAR(MAX), CONVERT(NUMERIC(38,
1295:                                                               20), CONVERT(VARBINARY(1), SUBSTRING(hex_Value,
1296:                                                               3, 1))
1297:                                           + CONVERT(VARBINARY(1), SUBSTRING(hex_Value,
1298:                                                               4, 1))
1299:                                           + CONVERT(VARBINARY(1), 0)
1300:                                           + SUBSTRING(hex_Value, 5,
1301:                                                       LEN(hex_Value)))) --- NUMERIC
1302:                                      WHEN CONVERT(INT, SUBSTRING(hex_Value, 1,
1303:                                                               1)) = 167
1304:                                      THEN LTRIM(RTRIM(CONVERT(VARCHAR(MAX), SUBSTRING(hex_Value,
1305:                                                               9,
1306:                                                               LEN(hex_Value))))) --VARCHAR,CHAR
1307:                                      WHEN CONVERT(INT, SUBSTRING(hex_Value, 1,
1308:                                                               1)) = 36
1309:                                      THEN CONVERT(VARCHAR(MAX), CONVERT(UNIQUEIDENTIFIER, SUBSTRING(( hex_Value ),
1310:                                                               3, 20))) --UNIQUEIDENTIFIER
1311:                                      WHEN CONVERT(INT, SUBSTRING(hex_Value, 1,
1312:                                                               1)) = 61
1313:                                      THEN CONVERT(VARCHAR(MAX), CONVERT(DATETIME, CONVERT(VARBINARY(8000), REVERSE(SUBSTRING(hex_Value,
1314:                                                               3,
1315:                                                               LEN(hex_Value))))), 100) --DATETIME
1316:                                      WHEN CONVERT(INT, SUBSTRING(hex_Value, 1,
1317:                                                               1)) = 165
1318:                                      THEN '0x'
1319:                                           + SUBSTRING(( CASE WHEN CHARINDEX(0x,
1320:                                                               CAST('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
1321:                                                               'VARBINARY(8000)')) = 0
1322:                                                              THEN '0x'
1323:                                                              ELSE ''
1324:                                                         END )
1325:                                                       + CAST('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
1326:                                                               'varchar(max)'),
1327:                                                       11, LEN(hex_Value)) -- BINARY,VARBINARY
1328:                                 END )
1329:                     END AS FieldValue ,
1330:                     [RowLogContents] ,
1331:                     [Row ID] ,
1332:                     [Transaction ID] ,
1333:                     NULL ,
1334:                     NULL
1335:             FROM    @ColumnNameAndData
1336:             ORDER BY nullbit
1337:  
1338: --Find the user ID and date time
1339:     UPDATE  #temp_Data
1340:     SET     [Deleted By User Name] = SUSER_SNAME(B.[Transaction SID]),
1341:             [Deletion Date Time] = [Begin Time]
1342:     FROM    #temp_Data A
1343:             INNER JOIN fn_dblog(NULL, NULL) B ON A.[Transaction ID] = B.[Transaction ID]
1344:     WHERE   B.[Operation] = 'LOP_BEGIN_XACT'
1345:             AND B.[Context] = 'LCX_NULL'
1346:             AND B.[Transaction Name] IN ('DELETE', 'user_transaction')
1347:  
1348: --Create the column name in the same order to do pivot table.
1349:  
1350:     DECLARE @FieldName VARCHAR(MAX)
1351:     DECLARE @AdditionalField VARCHAR(MAX)
1352:     SET @FieldName = STUFF(( SELECT ','
1353:                                     + CAST(QUOTENAME([Name]) AS VARCHAR(MAX))
1354:                              FROM   syscolumns
1355:                              WHERE  id = OBJECT_ID(''
1356:                                                    + @SchemaName_n_TableName
1357:                                                    + '')
1358:                            FOR
1359:                              XML PATH('')
1360:                            ), 1, 1, '')
1361:  
1362: --Finally did pivot table and get the data back in the same format.
1363:  
1364:     SET @AdditionalField = @FieldName
1365:         + ' ,[Deleted By User Name],[Deletion Date Time]'
1366:  
1367:     SET @SQL = 'SELECT ' + @AdditionalField
1368:         + ' FROM #temp_Data PIVOT (Min([FieldValue]) FOR FieldName IN ('
1369:         + @FieldName + ')) AS pvt'
1370:     PRINT @SQL
1371:     EXEC sp_executesql @SQL
1372:  
1373: GO

 

對這個問題有興趣的朋友,可以參考亂馬的文章 [SQL]透過 Transaction Log(fn_dblog) 取回被刪除的資料