恢复SQL Server被误删除的数据(再扩展)

大家对本人之前的文章《恢复SQL Server被误删除的数据》 反应非常热烈,但是文章里的存储过程不能实现对备份出来的日志备份里所删数据的恢复

这个是一个缺陷,本人决定对这个存储过程扩展一下,支持对log backup文件里的delete语句进行恢复

实验步骤

1、首先先准备好测试表和测试语句

  1. USE [sss]
  2. GO
  3.  
  4. --建表
  5. CREATE TABLE testdelete
  6. (
  7. id INT IDENTITY(1, 1)
  8. NOT NULL
  9. PRIMARY KEY ,
  10. NAME VARCHAR(200) ,
  11. dt DATETIME
  12. )
  13.  
  14. --插入数据
  15. INSERT [dbo].[testdelete]
  16. ( [NAME], [dt] )
  17. VALUES ( 'aa', -- NAME - varchar(200)
  18. '2015-07-04 07:06:40' -- dt - datetime
  19. )
  20.  
  21. SELECT * FROM [dbo].[testdelete]
  22.  
  23. --删除数据
  24. DELETE FROM [dbo].[testdelete]

2、删除数据之后对数据库进行日志备份

  1. DECLARE @CurrentTime VARCHAR(50) ,
  2. @FileName VARCHAR(200)
  3. SET @CurrentTime = REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120),
  4. '-', '_'), ' ', '_'), ':', '')
  5. SET @FileName = 'c:\sss_logBackup_' + @CurrentTime + '.bak'
  6. BACKUP LOG [sss]
  7. TO DISK=@FileName WITH FORMAT

4、建立存储过程

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

5、在C盘看到备份出来的日志备份文件

6、存储过程的两种调用方式

--存储过程依然保持着两种调用方式
EXEC Recover_Deleted_Data_BylogBackup_Proc 'sss','dbo.testdelete',N'C:\sss_logBackup_2015_07_04_150756.BAK'
GO EXEC Recover_Deleted_Data_BylogBackup_Proc 'sss','dbo.testdelete',N'C:\sss_logBackup_2015_07_04_150756.BAK','2012-06-01','2016-06-30'
GO

可以看到被误删的那条数据.


为什麽要扩展这个存储过程

因为进行了日志备份之后,原先的delete语句的log record可能已经不存在于ldf文件里面,这时候要恢复被那条delete语句删除的数据就需要读取

log backup文件里面的log record来进行恢复

对比图

Recover_Deleted_Data_Proc

Recover_Deleted_Data_BylogBackup_Proc

因为很多公司为了数据安全,一般会对数据库半个小时或者15分钟做一次日志备份,目的是做日志传送或者及时把数据库备份拷走

考虑到这种情况,本人决定扩展一下这个存储过程,其实原理也很简单,就是把fn_dblog函数替换为fn_dump_dblog函数

在文章《恢复SQL Server被误删除的数据》发布之后,有很多人通过QQ咨询我,为什麽执行了你的存储过程之后会显示

There is no data in the log as per the search criteria

我发现原因基本上有两个:

(1)数据库从来没有做过完整备份

(2)因为数据库实例下有一个job定时对数据库做日志备份,误删除了数据之后(误执行delete语句之后),刚好那个job到达运行时间,对数据库进行了日志备份

对于第一种情况,可以参考本人写的这篇文章《您真的理解了SQLSERVER的日志链了吗?》,文章里面有解释

对于第二种情况,可以使用本篇文章的方法,回想一下delete语句的执行时间,然后指定日志备份的备份文件进行恢复

--指定日志备份的备份文件
EXEC Recover_Deleted_Data_BylogBackup_Proc 'sss','dbo.testdelete',N'C:\sss_logBackup_2015_07_04_150756.BAK'
GO

如有不对的地方,欢迎大家拍砖o(∩_∩)o 

本文版权归作者所有,未经作者同意不得转载。

恢复SQL Server被误删除的数据(再扩展)的更多相关文章

  1. 恢复SQL Server被误删除的数据

    恢复SQL Server被误删除的数据 <恢复SQL Server被误删除的数据(再扩展)> 地址:http://www.cnblogs.com/lyhabc/p/4620764.html ...

  2. SQL Server中误删除数据的恢复

    SQL Server中误删除数据的恢复本来不是件难事,从事务日志恢复即可.但是,这个恢复需要有两个前提条件: 1. 至少有一个误删除之前的数据库完全备份. 2. 数据库的恢复模式(Recovery m ...

  3. ApexSQL Log 从意外UPDATE和DELETE操作中恢复SQL Server数据

    下载地址:https://www.apexsql.com/download.aspx 如何从意外UPDATE和DELETE操作中恢复SQL Server数据 ApexSQL Log 从意外UPDATE ...

  4. 通过日志恢复SQL Server的历史数据

    通过日志恢复SQL Server的历史数据 Posted on 2008-11-14 21:47 代码乱了 阅读(4658) 评论(10)  编辑 收藏 园子里前段时间发过一篇通过日志恢复MSSQL数 ...

  5. .SQL Server中 image类型数据的比较

    原文:.SQL Server中 image类型数据的比较 在SQL Server中如果你对text.ntext或者image数据类型的数据进行比较.将会提示:不能比较或排序 text.ntext 和 ...

  6. 如何恢复SQL Server 中的Master库

    如何恢复SQL Server 2005中的Master库 2011-05-10 16:34 Vegas Lee 博客园 我要评论(0) 字号:T | T   master库对于SQLServer来说, ...

  7. C#同步SQL Server数据库中的数据--数据库同步工具[同步新数据]

    C#同步SQL Server数据库中的数据 1. 先写个sql处理类: using System; using System.Collections.Generic; using System.Dat ...

  8. 使用XML向SQL Server 2005批量写入数据——一次有关XML时间格式的折腾经历

    原文:使用XML向SQL Server 2005批量写入数据——一次有关XML时间格式的折腾经历 常常遇到需要向SQL Server插入批量数据,然后在存储过程中对这些数据进行进一步处理的情况.存储过 ...

  9. Sql Server 存储过程中查询数据无法使用 Union(All)

    原文:Sql Server 存储过程中查询数据无法使用 Union(All) 微软Sql Server数据库中,书写存储过程时,关于查询数据,无法使用Union(All)关联多个查询. 1.先看一段正 ...

随机推荐

  1. Asp.net MVC 传递数据 从前台到后台,包括单个对象,多个对象,集合

    今天为大家分享下 Asp.net MVC 将数据从前台传递到后台的几种方式. 环境:VS2013,MVC5.0框架 1.基本数据类型 我们常见有传递 int, string, bool, double ...

  2. 几个比较”有意思“的JS脚本

    1.获取内网和公网真实IP地址(引用地址) <!DOCTYPE html> <html> <head> <meta http-equiv="Cont ...

  3. HTML文档声明

    前面的话   HTML文档通常以类型声明开始,该声明将帮助浏览器确定其尝试解析和显示的HTML文档类型.本文将详细介绍文档声明DOCTYPE 特点   文档声明必须是HTML文档的第一行.且顶格显示, ...

  4. .NET跨平台之运行与Linux上的Jexus服务器

    谈及.NET跨平台,已经不是什么稀奇的事儿.今天我们就以Jexus服务器的部署为例.简单示范下.在这里,我用VMWare虚拟机来搭建Linux运行环境. Linux,我们选择CentOS7.大家可以前 ...

  5. class-dump 反编译私有的库和应用

    一.下载并安装class-dump 下载class-dump-3.5.dmg  点击下载 下载完成以后双击.dmg的文件,将里面的class-dump拷贝到/usr/local/bin 设置权限chm ...

  6. ASP.NET MVC 5 系列 学习笔记 目录 (持续更新...)

    前言: 记得当初培训的时候,学习的还是ASP.NET,现在回想一下,图片水印.统计人数.过滤器....HttpHandler是多么的经典! 不过后来接触到了MVC,便立马爱上了它.Model-View ...

  7. Microsoft Visual Studio 2015 下载、注册、安装过程、功能列表、问题解决

    PS:请看看回复.可能会有文章里没有提到的问题.也许会对你有帮助哦~ 先上一张最终的截图吧: VS2015正式版出了,虽然没有Ultimate旗舰版,不过也是好激动的说.哈哈.可能有的小伙伴,由于工作 ...

  8. Linux网络属性配置

    目录 IP地址分类 如何将Linux主机接入到网络中 网络接口的命名方式 ifcfg系列命令 如何配置主机名 如何配置DNS服务器指向 iproute2系列命令 Linux管理网络服务 永久生效配置路 ...

  9. 如何开发FineReport的自定义控件?

    FineReport作为插件化开发的报表软件,有些特殊需求的功能需要自己开发,开发的插件包帆软官方有提提供,可以去帆软论坛上找,本文将主要介绍如何开发一个自定义控件,这里讲讲方法论. 第一步:实例化一 ...

  10. MyBatis5:MyBatis集成Spring事物管理(上篇)

    前言 有些日子没写博客了,主要原因一个是工作,另一个就是健身,因为我们不仅需要努力工作,也需要有健康的身体嘛. 那有看LZ博客的网友朋友们放心,LZ博客还是会继续保持更新,只是最近两三个月LZ写博客相 ...