----创建存储过程
CREATE PROCEDURE Recover_Deleted_Data_Proc
@Database_Name NVARCHAR(MAX) ,
@SchemaName_n_TableName NVARCHAR(MAX) ,
@Date_From DATETIME
=
'
1900/01/01
'
,
@Date_To DATETIME
=
'
9999/12/31
'
AS
DECLARE @RowLogContents VARBINARY(
8000
)
DECLARE @TransactionID NVARCHAR(MAX)
DECLARE @AllocUnitID BIGINT
DECLARE @AllocUnitName NVARCHAR(MAX)
DECLARE @SQL NVARCHAR(MAX)
DECLARE @Compatibility_Level INT
SELECT @Compatibility_Level
=
dtb.compatibility_level
FROM master.sys.databases AS dtb
WHERE dtb.name
=
@Database_Name
IF ISNULL(@Compatibility_Level,
0
) <=
80
BEGIN
RAISERROR(
'
The compatibility level should be equal to or greater SQL SERVER 2005 (90)
'
,
16
,
1
)
RETURN
END
IF ( SELECT COUNT(
*
)
FROM INFORMATION_SCHEMA.TABLES
WHERE [TABLE_SCHEMA]
+
'
.
'
+ [TABLE_NAME] =
@SchemaName_n_TableName
)
=
0
BEGIN
RAISERROR(
'
Could not found the table in the defined database
'
,
16
,
1
)
RETURN
END
DECLARE @bitTable TABLE
(
[ID] INT ,
[Bitvalue] INT
)
--Create table to
set
the bit position of one
byte
.
INSERT INTO @bitTable
SELECT
0
,
2
UNION ALL
SELECT
1
,
2
UNION ALL
SELECT
2
,
4
UNION ALL
SELECT
3
,
8
UNION ALL
SELECT
4
,
16
UNION ALL
SELECT
5
,
32
UNION ALL
SELECT
6
,
64
UNION ALL
SELECT
7
,
128
--
Create table to collect the row data.
DECLARE @DeletedRecords TABLE
(
[Row ID] INT IDENTITY(
1
,
1
) ,
[RowLogContents] VARBINARY(
8000
) ,
[AllocUnitID] BIGINT ,
[Transaction ID] NVARCHAR(MAX) ,
[FixedLengthData] SMALLINT ,
[TotalNoOfCols] SMALLINT ,
[NullBitMapLength] SMALLINT ,
[NullBytes] VARBINARY(
8000
) ,
[TotalNoofVarCols] SMALLINT ,
[ColumnOffsetArray] VARBINARY(
8000
) ,
[VarColumnStart] SMALLINT ,
[Slot ID] INT ,
[NullBitMap] VARCHAR(MAX)
)
--Create a common table expression to
get
all the row data plus how many bytes we have
for
each row.
;
WITH RowData
AS ( SELECT [RowLog Contents
0
] AS [RowLogContents] ,
[AllocUnitID] AS [AllocUnitID] ,
[Transaction ID] AS [Transaction ID]
--[Fixed Length Data] = Substring (RowLog content
0
, Status Bit A+ Status Bit B +
1
,
2
bytes)
,
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) AS [FixedLengthData] --
@FixedLengthData
-- [TotalnoOfCols] = Substring (RowLog content
0
, [Fixed Length Data] +
1
,
2
bytes)
,
CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
1
,
2
)))) AS [TotalNoOfCols]
--[NullBitMapLength]=ceiling([Total No of Columns] /
8.0
)
,
CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
1
,
2
)))) /
8.0
)) AS [NullBitMapLength]
--[Null Bytes] = Substring (RowLog content
0
, Status Bit A+ Status Bit B + [Fixed Length Data] +
1
, [NullBitMapLength] )
,
SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
3
,
CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
1
,
2
)))) /
8.0
))) AS [NullBytes]
--[TotalNoofVarCols] = Substring (RowLog content
0
, Status Bit A+ Status Bit B + [Fixed Length Data] +
1
, [Null Bitmap length] +
2
)
,
( CASE WHEN SUBSTRING([RowLog Contents
0
],
1
,
1
) IN (
0x10
,
0x30
,
0x70
)
THEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
3
+ CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
1
,
2
)))) /
8.0
)),
2
))))
ELSE NULL
END ) AS [TotalNoofVarCols]
--[ColumnOffsetArray]= Substring (RowLog content
0
, Status Bit A+ Status Bit B + [Fixed Length Data] +
1
, [Null Bitmap length] +
2
, [TotalNoofVarCols]*
2
)
,
( CASE WHEN SUBSTRING([RowLog Contents
0
],
1
,
1
) IN (
0x10
,
0x30
,
0x70
)
THEN SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
3
+ CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
1
,
2
)))) /
8.0
))
+
2
,
( CASE WHEN SUBSTRING([RowLog Contents
0
],
1
,
1
) IN (
0x10
,
0x30
,
0x70
)
THEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
3
+ CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
1
,
2
)))) /
8.0
)),
2
))))
ELSE NULL
END )
*
2
)
ELSE NULL
END ) AS [ColumnOffsetArray]
-- Variable column Start = Status Bit A+ Status Bit B + [Fixed Length Data] + [Null Bitmap length] +
2
+([TotalNoofVarCols]*
2
)
,
CASE WHEN SUBSTRING([RowLog Contents
0
],
1
,
1
) IN (
0x10
,
0x30
,
0x70
)
THEN ( CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
4
+ CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
1
,
2
)))) /
8.0
))
+ ( ( CASE WHEN SUBSTRING([RowLog Contents
0
],
1
,
1
) IN (
0x10
,
0x30
,
0x70
)
THEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
3
+ CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([RowLog Contents
0
],
2
+
1
,
2
)))) +
1
,
2
)))) /
8.0
)),
2
))))
ELSE NULL
END )
*
2
) )
ELSE NULL
END AS [VarColumnStart] ,
[Slot ID]
FROM sys.fn_dblog(NULL, NULL)
WHERE AllocUnitId IN (
SELECT [Allocation_unit_id]
FROM sys.allocation_units allocunits
INNER JOIN sys.partitions partitions ON ( allocunits.type IN (
1
,
3
)
AND partitions.hobt_id
=
allocunits.container_id
)
OR ( allocunits.type
=
2
AND partitions.partition_id
=
allocunits.container_id
)
WHERE object_id
= OBJECT_ID(
''
+
@SchemaName_n_TableName
+
''
) )
AND Context IN (
'
LCX_MARK_AS_GHOST
'
,
'
LCX_HEAP
'
)
AND Operation IN (
'
LOP_DELETE_ROWS
'
)
AND SUBSTRING([RowLog Contents
0
],
1
,
1
) IN (
0x10
,
0x30
,
0x70
)
/*
Use this subquery to filter the date
*/
AND [TRANSACTION ID] IN (
SELECT DISTINCT
[TRANSACTION ID]
FROM sys.fn_dblog(NULL, NULL)
WHERE Context IN (
'
LCX_NULL
'
)
AND Operation IN (
'
LOP_BEGIN_XACT
'
)
AND [Transaction Name] IN (
'
DELETE
'
,
'
user_transaction
'
)
AND CONVERT(NVARCHAR(
11
), [Begin Time]) BETWEEN @Date_From
AND
@Date_To )
),
--Use
this
technique to repeate the row till the no of bytes of the row.
N1 ( n )
AS ( SELECT
1
UNION ALL
SELECT
1
),
N2 ( n )
AS ( SELECT
1
FROM N1 AS X ,
N1 AS Y
),
N3 ( n )
AS ( SELECT
1
FROM N2 AS X ,
N2 AS Y
),
N4 ( n )
AS ( SELECT ROW_NUMBER() OVER ( ORDER BY X.n )
FROM N3 AS X ,
N3 AS Y
)
INSERT INTO @DeletedRecords
SELECT RowLogContents ,
[AllocUnitID] ,
[Transaction ID] ,
[FixedLengthData] ,
[TotalNoOfCols] ,
[NullBitMapLength] ,
[NullBytes] ,
[TotalNoofVarCols] ,
[ColumnOffsetArray] ,
[VarColumnStart] ,
[Slot ID]
---Get the Null value against each column (
1
means
null
zero means not
null
)
,
[NullBitMap]
=
( REPLACE(STUFF(( SELECT
'
,
'
+
( CASE
WHEN [ID]
=
0
THEN CONVERT(NVARCHAR(
1
), ( SUBSTRING(NullBytes,
n,
1
) %
2
))
ELSE CONVERT(NVARCHAR(
1
), ( ( SUBSTRING(NullBytes,
n,
1
)
/
[Bitvalue] )
%
2
))
END )
--
as
[nullBitMap]
FROM N4 AS Nums
JOIN RowData AS C ON n
<=
NullBitMapLength
CROSS JOIN @bitTable
WHERE
C.[RowLogContents]
=
D.[RowLogContents]
ORDER BY [RowLogContents] ,
n ASC
FOR
XML PATH(
''
)
),
1
,
1
,
''
),
'
,
'
,
''
) )
FROM RowData D
IF ( SELECT COUNT(
*
)
FROM @DeletedRecords
)
=
0
BEGIN
RAISERROR(
'
There is no data in the log as per the search criteria
'
,
16
,
1
)
RETURN
END
DECLARE @ColumnNameAndData TABLE
(
[Row ID] INT ,
[Rowlogcontents] VARBINARY(MAX) ,
[NAME] SYSNAME ,
[nullbit] SMALLINT ,
[leaf_offset] SMALLINT ,
[length] SMALLINT ,
[system_type_id] TINYINT ,
[bitpos] TINYINT ,
[xprec] TINYINT ,
[xscale] TINYINT ,
[is_null] INT ,
[Column value Size] INT ,
[Column Length] INT ,
[hex_Value] VARBINARY(MAX) ,
[Slot ID] INT ,
[Update] INT
)
--
Create common table expression and join it with the rowdata table
-- to
get
each column details
/*
This part is for variable data columns
*/
--
@RowLogContents,
--(col.columnOffValue - col.columnLength) +
1
,
--
col.columnLength
--
)
INSERT INTO @ColumnNameAndData
SELECT [Row ID] ,
Rowlogcontents ,
NAME ,
cols.leaf_null_bit AS nullbit ,
leaf_offset ,
ISNULL(syscolumns.length, cols.max_length) AS [length] ,
cols.system_type_id ,
cols.leaf_bit_position AS bitpos ,
ISNULL(syscolumns.xprec, cols.precision) AS xprec ,
ISNULL(syscolumns.xscale, cols.scale) AS xscale ,
SUBSTRING([nullBitMap], cols.leaf_null_bit,
1
) AS is_null ,
( CASE WHEN leaf_offset
<
1
AND SUBSTRING([nullBitMap], cols.leaf_null_bit,
1
) =
0
THEN ( CASE WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) >
30000
THEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
))))
- POWER(
2
,
15
)
ELSE CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
))))
END )
END ) AS [Column value Size] ,
( CASE WHEN leaf_offset
<
1
AND SUBSTRING([nullBitMap], cols.leaf_null_bit,
1
) =
0
THEN ( CASE WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) >
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
<
30000
THEN ( CASE WHEN [System_type_id] IN (
35
,
34
,
99
) THEN
16
ELSE
24
END )
WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) >
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
>
30000
THEN ( CASE WHEN [System_type_id] IN (
35
,
34
,
99
) THEN
16
ELSE
24
END )
--
24
WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) <
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
<
30000
THEN ( CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
))))
- ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart]) )
WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) <
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
>
30000
THEN POWER(
2
,
15
)
+ CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
))))
- ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
END )
END ) AS [Column Length] ,
( CASE WHEN SUBSTRING([nullBitMap], cols.leaf_null_bit,
1
) =
1
THEN NULL
ELSE SUBSTRING(Rowlogcontents,
( ( CASE WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) >
30000
THEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
))))
- POWER(
2
,
15
)
ELSE CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
))))
END )
- ( CASE WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) >
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
<
30000
THEN ( CASE
WHEN [System_type_id] IN (
35
,
34
,
99
)
THEN
16
ELSE
24
END )
--
24
WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) >
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
>
30000
THEN ( CASE
WHEN [System_type_id] IN (
35
,
34
,
99
)
THEN
16
ELSE
24
END )
--
24
WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) <
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
<
30000
THEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
))))
- ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) <
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
>
30000
THEN POWER(
2
,
15
)
+ CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
))))
- ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
END ) )
+
1
,
( CASE WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) >
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
<
30000
THEN ( CASE WHEN [System_type_id] IN (
35
,
34
,
99
)
THEN
16
ELSE
24
END )
--
24
WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) >
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
>
30000
THEN ( CASE WHEN [System_type_id] IN (
35
,
34
,
99
)
THEN
16
ELSE
24
END )
--
24
WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) <
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
<
30000
THEN ABS(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
))))
- ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart]))
WHEN CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
)))) <
30000
AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
>
30000
THEN POWER(
2
,
15
)
+ CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
leaf_offset
* -
1
) -
1
,
2
))))
- ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(
2
), REVERSE(SUBSTRING([ColumnOffsetArray],
(
2
*
( ( leaf_offset
* -
1
) -
1
) )
-
1
,
2
)))),
0
),
[varColumnStart])
END ))
END ) AS hex_Value ,
[Slot ID] ,
0
FROM @DeletedRecords A
INNER JOIN sys.allocation_units allocunits ON A.[AllocUnitId]
=
allocunits.[Allocation_Unit_Id]
INNER JOIN sys.partitions partitions ON ( allocunits.type IN (
1
,
3
)
AND partitions.hobt_id
=
allocunits.container_id
)
OR ( allocunits.type
=
2
AND partitions.partition_id
=
allocunits.container_id
)
INNER JOIN sys.system_internals_partition_columns cols ON cols.partition_id
=
partitions.partition_id
LEFT OUTER JOIN syscolumns ON syscolumns.id
=
partitions.object_id
AND syscolumns.colid
=
cols.partition_column_id
WHERE leaf_offset
<
0
UNION
/*
This part is for fixed data columns
*/
SELECT [Row ID] ,
Rowlogcontents ,
NAME ,
cols.leaf_null_bit AS nullbit ,
leaf_offset ,
ISNULL(syscolumns.length, cols.max_length) AS [length] ,
cols.system_type_id ,
cols.leaf_bit_position AS bitpos ,
ISNULL(syscolumns.xprec, cols.precision) AS xprec ,
ISNULL(syscolumns.xscale, cols.scale) AS xscale ,
SUBSTRING([nullBitMap], cols.leaf_null_bit,
1
) AS is_null ,
( SELECT TOP
1
ISNULL(SUM(CASE WHEN C.leaf_offset
>
1
THEN max_length
ELSE
0
END),
0
)
FROM sys.system_internals_partition_columns C
WHERE cols.partition_id
=
C.partition_id
AND C.leaf_null_bit
<
cols.leaf_null_bit
)
+
5
AS [Column value Size] ,
syscolumns.length AS [Column Length] ,
CASE WHEN SUBSTRING([nullBitMap], cols.leaf_null_bit,
1
) =
1
THEN NULL
ELSE SUBSTRING(Rowlogcontents,
( SELECT TOP
1
ISNULL(SUM(CASE
WHEN C.leaf_offset
>
1
AND C.leaf_bit_position
=
0
THEN max_length
ELSE
0
END),
0
)
FROM sys.system_internals_partition_columns C
WHERE cols.partition_id
=
C.partition_id
AND C.leaf_null_bit
<
cols.leaf_null_bit
)
+
5
, syscolumns.length)
END AS hex_Value ,
[Slot ID] ,
0
FROM @DeletedRecords A
INNER JOIN sys.allocation_units allocunits ON A.[AllocUnitId]
=
allocunits.[Allocation_Unit_Id]
INNER JOIN sys.partitions partitions ON ( allocunits.type IN (
1
,
3
)
AND partitions.hobt_id
=
allocunits.container_id
)
OR ( allocunits.type
=
2
AND partitions.partition_id
=
allocunits.container_id
)
INNER JOIN sys.system_internals_partition_columns cols ON cols.partition_id
=
partitions.partition_id
LEFT OUTER JOIN syscolumns ON syscolumns.id
=
partitions.object_id
AND syscolumns.colid
=
cols.partition_column_id
WHERE leaf_offset
>
0
ORDER BY nullbit
DECLARE @BitColumnByte AS INT
SELECT @BitColumnByte
= CONVERT(INT, CEILING(COUNT(*) /
8.0
))
FROM @ColumnNameAndData
WHERE [System_Type_id]
=
104
;
WITH N1 ( n )
AS ( SELECT
1
UNION ALL
SELECT
1
),
N2 ( n )
AS ( SELECT
1
FROM N1 AS X ,
N1 AS Y
),
N3 ( n )
AS ( SELECT
1
FROM N2 AS X ,
N2 AS Y
),
N4 ( n )
AS ( SELECT ROW_NUMBER() OVER ( ORDER BY X.n )
FROM N3 AS X ,
N3 AS Y
),
CTE
AS ( SELECT RowLogContents ,
[nullbit] ,
[BitMap]
= CONVERT(VARBINARY(
1
), CONVERT(INT, SUBSTRING(( REPLACE(STUFF(( SELECT
'
,
'
+
( CASE
WHEN [ID]
=
0
THEN CONVERT(NVARCHAR(
1
), ( SUBSTRING(hex_Value,
n,
1
) %
2
))
ELSE CONVERT(NVARCHAR(
1
), ( ( SUBSTRING(hex_Value,
n,
1
)
/
[Bitvalue] )
%
2
))
END )
--
as
[nullBitMap]
FROM
N4 AS Nums
JOIN @ColumnNameAndData
AS C ON n
<=
@BitColumnByte
AND [System_Type_id]
=
104
AND bitpos
=
0
CROSS JOIN @bitTable
WHERE
C.[RowLogContents]
=
D.[RowLogContents]
ORDER BY [RowLogContents] ,
n ASC
FOR
XML
PATH(
''
)
),
1
,
1
,
''
),
'
,
'
,
''
) ),
bitpos
+
1
,
1
)))
FROM @ColumnNameAndData D
WHERE [System_Type_id]
=
104
)
UPDATE A
SET [hex_Value]
=
[BitMap]
FROM @ColumnNameAndData A
INNER JOIN CTE B ON A.[RowLogContents]
=
B.[RowLogContents]
AND A.[nullbit]
=
B.[nullbit]
/*
*************Check for BLOB DATA TYPES*****************************
*/
DECLARE @Fileid INT
DECLARE @Pageid INT
DECLARE @Slotid INT
DECLARE @CurrentLSN INT
DECLARE @LinkID INT
DECLARE @Context VARCHAR(
50
)
DECLARE @ConsolidatedPageID VARCHAR(MAX)
DECLARE @LCX_TEXT_MIX VARBINARY(MAX)
DECLARE @temppagedata TABLE
(
[ParentObject] SYSNAME ,
[Object] SYSNAME ,
[Field] SYSNAME ,
[Value] SYSNAME
)
DECLARE @pagedata TABLE
(
[Page ID] SYSNAME ,
[File IDS] INT ,
[Page IDS] INT ,
[AllocUnitId] BIGINT ,
[ParentObject] SYSNAME ,
[Object] SYSNAME ,
[Field] SYSNAME ,
[Value] SYSNAME
)
DECLARE @ModifiedRawData TABLE
(
[ID] INT IDENTITY(
1
,
1
) ,
[PAGE ID] VARCHAR(MAX) ,
[FILE IDS] INT ,
[PAGE IDS] INT ,
[Slot ID] INT ,
[AllocUnitId] BIGINT ,
[RowLog Contents 0_var] VARCHAR(MAX) ,
[RowLog Length] VARCHAR(
50
) ,
[RowLog Len] INT ,
[RowLog Contents
0
] VARBINARY(MAX) ,
[Link ID] INT DEFAULT (
0
) ,
[Update] INT
)
DECLARE Page_Data_Cursor CURSOR
FOR
/*
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
*/
SELECT LTRIM(RTRIM(REPLACE([Description],
'
Deallocated
'
,
''
))) AS [PAGE ID] ,
[Slot ID] ,
[AllocUnitId] ,
NULL AS [RowLog Contents
0
] ,
NULL AS [RowLog Contents
0
] ,
Context
FROM sys.fn_dblog(NULL, NULL)
WHERE AllocUnitId IN (
SELECT [Allocation_unit_id]
FROM sys.allocation_units allocunits
INNER JOIN sys.partitions partitions ON ( allocunits.type IN (
1
,
3
)
AND partitions.hobt_id
=
allocunits.container_id
)
OR ( allocunits.type
=
2
AND partitions.partition_id
=
allocunits.container_id
)
WHERE object_id
= OBJECT_ID(
''
+
@SchemaName_n_TableName
+
''
) )
AND Operation IN (
'
LOP_MODIFY_ROW
'
)
AND [Context] IN (
'
LCX_PFS
'
)
AND Description LIKE
'
%Deallocated%
'
/*
Use this subquery to filter the date
*/
AND [TRANSACTION ID] IN (
SELECT DISTINCT
[TRANSACTION ID]
FROM sys.fn_dblog(NULL, NULL)
WHERE Context IN (
'
LCX_NULL
'
)
AND Operation IN (
'
LOP_BEGIN_XACT
'
)
AND [Transaction Name]
=
'
DELETE
'
AND CONVERT(NVARCHAR(
11
), [Begin Time]) BETWEEN @Date_From
AND
@Date_To )
GROUP BY [Description] ,
[Slot ID] ,
[AllocUnitId] ,
Context
UNION
SELECT [PAGE ID] ,
[Slot ID] ,
[AllocUnitId] ,
SUBSTRING([RowLog Contents
0
],
15
,
LEN([RowLog Contents
0
])) AS [RowLog Contents
0
] ,
CONVERT(INT, SUBSTRING([RowLog Contents
0
],
7
,
2
)) ,
Context
--,CAST(RIGHT([Current LSN],
4
) AS INT) AS [Current LSN]
FROM sys.fn_dblog(NULL, NULL)
WHERE AllocUnitId IN (
SELECT [Allocation_unit_id]
FROM sys.allocation_units allocunits
INNER JOIN sys.partitions partitions ON ( allocunits.type IN (
1
,
3
)
AND partitions.hobt_id
=
allocunits.container_id
)
OR ( allocunits.type
=
2
AND partitions.partition_id
=
allocunits.container_id
)
WHERE object_id
= OBJECT_ID(
''
+
@SchemaName_n_TableName
+
''
) )
AND Context IN (
'
LCX_TEXT_MIX
'
)
AND Operation IN (
'
LOP_DELETE_ROWS
'
)
/*
Use this subquery to filter the date
*/
AND [TRANSACTION ID] IN (
SELECT DISTINCT
[TRANSACTION ID]
FROM sys.fn_dblog(NULL, NULL)
WHERE Context IN (
'
LCX_NULL
'
)
AND Operation IN (
'
LOP_BEGIN_XACT
'
)
AND [Transaction Name]
=
'
DELETE
'
AND CONVERT(NVARCHAR(
11
), [Begin Time]) BETWEEN @Date_From
AND
@Date_To )
/*
**************************************
*/
OPEN Page_Data_Cursor
FETCH NEXT FROM Page_Data_Cursor INTO @ConsolidatedPageID, @Slotid,
@AllocUnitID, @LCX_TEXT_MIX, @LinkID, @Context
WHILE @@FETCH_STATUS
=
0
BEGIN
DECLARE @hex_pageid AS VARCHAR(MAX)
/*
Page ID contains File Number and page number It looks like 0001:00000130.
In this example 0001 is file Number & 00000130 is Page Number & These numbers are in Hex format
*/
SET @Fileid
= SUBSTRING(@ConsolidatedPageID,
0
,
CHARINDEX(
'
:
'
, @ConsolidatedPageID)) -- Seperate File ID
from
Page ID
SET @hex_pageid
=
'
0x
'
+
SUBSTRING(@ConsolidatedPageID,
CHARINDEX(
'
:
'
,
@ConsolidatedPageID)
+
1
, LEN(@ConsolidatedPageID)) ---
Seperate the page ID
SELECT @Pageid
= CONVERT(INT, CAST(
''
AS XML).value(
'
xs:hexBinary(substring(sql:variable("@hex_pageid"),sql:column("t.pos")) )
'
,
'
varbinary(max)
'
)) -- Convert Page ID
from
hex to integer
FROM ( SELECT CASE SUBSTRING(@hex_pageid,
1
,
2
)
WHEN
'
0x
'
THEN
3
ELSE
0
END
) AS t ( pos )
IF @Context
=
'
LCX_PFS
'
BEGIN
DELETE @temppagedata
INSERT INTO @temppagedata
EXEC
(
'
DBCC PAGE(
'
+ @DataBase_Name +
'
,
'
+ @fileid +
'
,
'
+
@pageid
+
'
, 1) with tableresults,no_infomsgs;
'
);
INSERT INTO @pagedata
SELECT @ConsolidatedPageID ,
@fileid ,
@pageid ,
@AllocUnitID ,
[ParentObject] ,
[Object] ,
[Field] ,
[Value]
FROM @temppagedata
END
ELSE
IF @Context
=
'
LCX_TEXT_MIX
'
BEGIN
INSERT INTO @ModifiedRawData
SELECT @ConsolidatedPageID ,
@fileid ,
@pageid ,
@Slotid ,
@AllocUnitID ,
NULL ,
0
,
CONVERT(INT, CONVERT(VARBINARY, REVERSE(SUBSTRING(@LCX_TEXT_MIX,
11
,
2
)))) ,
@LCX_TEXT_MIX ,
@LinkID ,
0
END
FETCH NEXT FROM Page_Data_Cursor INTO @ConsolidatedPageID, @Slotid,
@AllocUnitID, @LCX_TEXT_MIX, @LinkID, @Context
END
CLOSE Page_Data_Cursor
DEALLOCATE Page_Data_Cursor
DECLARE @Newhexstring VARCHAR(MAX);
--The data
is
in
multiple rows
in
the page, so we need to convert it into one row
as
a single hex value.
--This hex value
is
in
string
format
INSERT INTO @ModifiedRawData
( [PAGE ID] ,
[FILE IDS] ,
[PAGE IDS] ,
[Slot ID] ,
[AllocUnitId] ,
[RowLog Contents 0_var] ,
[RowLog Length]
)
SELECT [Page ID] ,
[FILE IDS] ,
[PAGE IDS] ,
SUBSTRING([ParentObject],
CHARINDEX(
'
Slot
'
, [ParentObject]) +
4
,
( CHARINDEX(
'
Offset
'
, [ParentObject])
- ( CHARINDEX(
'
Slot
'
, [ParentObject]) +
4
) )
-
2
) AS [Slot ID] ,
[AllocUnitId] ,
SUBSTRING(( SELECT REPLACE(STUFF(( SELECT
REPLACE(SUBSTRING([Value],
CHARINDEX(
'
:
'
,
[Value])
+
1
,
CHARINDEX(
'
†
'
,
[Value])
- CHARINDEX(
'
:
'
,
[Value])),
'
†
'
,
''
)
FROM @pagedata C
WHERE B.[Page ID]
=
C.[Page ID]
AND SUBSTRING(B.[ParentObject],
CHARINDEX(
'
Slot
'
,
B.[ParentObject])
+
4
,
( CHARINDEX(
'
Offset
'
,
B.[ParentObject])
- ( CHARINDEX(
'
Slot
'
,
B.[ParentObject])
+
4
) )) =
SUBSTRING(C.[ParentObject],
CHARINDEX(
'
Slot
'
,
C.[ParentObject])
+
4
,
( CHARINDEX(
'
Offset
'
,
C.[ParentObject])
- ( CHARINDEX(
'
Slot
'
,
C.[ParentObject])
+
4
) ))
AND [Object] LIKE
'
%Memory Dump%
'
ORDER BY
'
0x
'
+
LEFT([Value],
CHARINDEX(
'
:
'
,
[Value])
-
1
)
FOR
XML PATH(
''
)
),
1
,
1
,
''
),
'
'
,
''
)
),
1
,
20000
) AS [Value] ,
SUBSTRING(( SELECT
'
0x
'
+
REPLACE(STUFF(( SELECT
REPLACE(SUBSTRING([Value],
CHARINDEX(
'
:
'
,
[Value])
+
1
,
CHARINDEX(
'
†
'
,
[Value])
- CHARINDEX(
'
:
'
,
[Value])),
'
†
'
,
''
)
FROM
@pagedata C
WHERE
B.[Page ID]
=
C.[Page ID]
AND SUBSTRING(B.[ParentObject],
CHARINDEX(
'
Slot
'
,
B.[ParentObject])
+
4
,
( CHARINDEX(
'
Offset
'
,
B.[ParentObject])
- ( CHARINDEX(
'
Slot
'
,
B.[ParentObject])
+
4
) )) =
SUBSTRING(C.[ParentObject],
CHARINDEX(
'
Slot
'
,
C.[ParentObject])
+
4
,
( CHARINDEX(
'
Offset
'
,
C.[ParentObject])
- ( CHARINDEX(
'
Slot
'
,
C.[ParentObject])
+
4
) ))
AND [Object] LIKE
'
%Memory Dump%
'
ORDER BY
'
0x
'
+
LEFT([Value],
CHARINDEX(
'
:
'
,
[Value])
-
1
)
FOR
XML PATH(
''
)
),
1
,
1
,
''
),
'
'
,
''
)
),
7
,
4
) AS [Length]
FROM @pagedata B
WHERE [Object] LIKE
'
%Memory Dump%
'
GROUP BY [Page ID] ,
[FILE IDS] ,
[PAGE IDS] ,
[ParentObject] ,
[AllocUnitId]
--
,[Current LSN]
ORDER BY [Slot ID]
UPDATE @ModifiedRawData
SET [RowLog Len]
= CONVERT(VARBINARY(
8000
), REVERSE(CAST(
''
AS XML).value(
'
xs:hexBinary(substring(sql:column("[RowLog Length]"),0))
'
,
'
varbinary(Max)
'
)))
FROM @ModifiedRawData
WHERE [LINK ID]
=
0
UPDATE @ModifiedRawData
SET [RowLog Contents
0
] = CAST(
''
AS XML).value(
'
xs:hexBinary(substring(sql:column("[RowLog Contents 0_var]"),0))
'
,
'
varbinary(Max)
'
)
FROM @ModifiedRawData
WHERE [LINK ID]
=
0
UPDATE B
SET B.[RowLog Contents
0
] = ( CASE WHEN A.[RowLog Contents
0
] IS NOT NULL
AND C.[RowLog Contents
0
] IS NOT NULL
THEN A.[RowLog Contents
0
]
+ C.[RowLog Contents
0
]
WHEN A.[RowLog Contents
0
] IS NULL
AND C.[RowLog Contents
0
] IS NOT NULL
THEN C.[RowLog Contents
0
]
WHEN A.[RowLog Contents
0
] IS NOT NULL
AND C.[RowLog Contents
0
] IS NULL
THEN A.[RowLog Contents
0
]
END ) ,
B.[Update]
= ISNULL(B.[Update],
0
) +
1
FROM @ModifiedRawData B
LEFT JOIN @ModifiedRawData A ON A.[Page IDS]
= CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents
0
],
15
+
14
,
2
))))
AND A.[File IDS]
= CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents
0
],
19
+
14
,
2
))))
AND A.[Link ID]
=
B.[Link ID]
LEFT JOIN @ModifiedRawData C ON C.[Page IDS]
= CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents
0
],
27
+
14
,
2
))))
AND C.[File IDS]
= CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents
0
],
31
+
14
,
2
))))
AND C.[Link ID]
=
B.[Link ID]
WHERE ( A.[RowLog Contents
0
] IS NOT NULL
OR C.[RowLog Contents
0
] IS NOT NULL
)
UPDATE B
SET B.[RowLog Contents
0
] = ( CASE WHEN A.[RowLog Contents
0
] IS NOT NULL
AND C.[RowLog Contents
0
] IS NOT NULL
THEN A.[RowLog Contents
0
]
+ C.[RowLog Contents
0
]
WHEN A.[RowLog Contents
0
] IS NULL
AND C.[RowLog Contents
0
] IS NOT NULL
THEN C.[RowLog Contents
0
]
WHEN A.[RowLog Contents
0
] IS NOT NULL
AND C.[RowLog Contents
0
] IS NULL
THEN A.[RowLog Contents
0
]
END )
--,B.[Update]=ISNULL(B.[Update],
0
)+
1
FROM @ModifiedRawData B
LEFT JOIN @ModifiedRawData A ON A.[Page IDS]
= CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents
0
],
15
+
14
,
2
))))
AND A.[File IDS]
= CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents
0
],
19
+
14
,
2
))))
AND A.[Link ID]
<>
B.[Link ID]
AND B.[Update]
=
0
LEFT JOIN @ModifiedRawData C ON C.[Page IDS]
= CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents
0
],
27
+
14
,
2
))))
AND C.[File IDS]
= CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents
0
],
31
+
14
,
2
))))
AND C.[Link ID]
<>
B.[Link ID]
AND B.[Update]
=
0
WHERE ( A.[RowLog Contents
0
] IS NOT NULL
OR C.[RowLog Contents
0
] IS NOT NULL
)
UPDATE @ModifiedRawData
SET [RowLog Contents
0
] = ( CASE WHEN [RowLog Len] >=
8000
THEN SUBSTRING([RowLog Contents
0
],
15
, [RowLog Len])
WHEN [RowLog Len]
<
8000
THEN SUBSTRING([RowLog Contents
0
],
15
+
6
,
CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([RowLog Contents
0
],
15
,
6
)))))
END )
FROM @ModifiedRawData
WHERE [LINK ID]
=
0
UPDATE @ColumnNameAndData
SET [hex_Value]
= [RowLog Contents
0
]
--,A.[Update]=A.[Update]+
1
FROM @ColumnNameAndData A
INNER JOIN @ModifiedRawData B ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
17
,
4
)))) =
[PAGE IDS]
AND CONVERT(INT, SUBSTRING([hex_value],
9
,
2
)) =
B.[Link ID]
WHERE [System_Type_Id] IN (
99
,
167
,
175
,
231
,
239
,
241
,
165
,
98
)
AND [Link ID]
<>
0
UPDATE @ColumnNameAndData
SET [hex_Value]
= ( CASE WHEN B.[RowLog Contents
0
] IS NOT NULL
AND C.[RowLog Contents
0
] IS NOT NULL
THEN B.[RowLog Contents
0
]
+ C.[RowLog Contents
0
]
WHEN B.[RowLog Contents
0
] IS NULL
AND C.[RowLog Contents
0
] IS NOT NULL
THEN C.[RowLog Contents
0
]
WHEN B.[RowLog Contents
0
] IS NOT NULL
AND C.[RowLog Contents
0
] IS NULL
THEN B.[RowLog Contents
0
]
END )
--,A.[Update]=A.[Update]+
1
FROM @ColumnNameAndData A
LEFT JOIN @ModifiedRawData B ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
5
,
4
)))) =
B.[PAGE IDS]
AND B.[Link ID]
=
0
LEFT JOIN @ModifiedRawData C ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
17
,
4
)))) =
C.[PAGE IDS]
AND C.[Link ID]
=
0
WHERE [System_Type_Id] IN (
99
,
167
,
175
,
231
,
239
,
241
,
165
,
98
)
AND ( B.[RowLog Contents
0
] IS NOT NULL
OR C.[RowLog Contents
0
] IS NOT NULL
)
UPDATE @ColumnNameAndData
SET [hex_Value]
= [RowLog Contents
0
]
--,A.[Update]=A.[Update]+
1
FROM @ColumnNameAndData A
INNER JOIN @ModifiedRawData B ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
9
,
4
)))) =
[PAGE IDS]
AND CONVERT(INT, SUBSTRING([hex_value],
3
,
2
)) =
[Link ID]
WHERE [System_Type_Id] IN (
35
,
34
,
99
)
AND [Link ID]
<>
0
UPDATE @ColumnNameAndData
SET [hex_Value]
= [RowLog Contents
0
]
--,A.[Update]=A.[Update]+
10
FROM @ColumnNameAndData A
INNER JOIN @ModifiedRawData B ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
9
,
4
)))) =
[PAGE IDS]
WHERE [System_Type_Id] IN (
35
,
34
,
99
)
AND [Link ID]
=
0
UPDATE @ColumnNameAndData
SET [hex_Value]
= [RowLog Contents
0
]
--,A.[Update]=A.[Update]+
1
FROM @ColumnNameAndData A
INNER JOIN @ModifiedRawData B ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
15
,
4
)))) =
[PAGE IDS]
WHERE [System_Type_Id] IN (
35
,
34
,
99
)
AND [Link ID]
=
0
UPDATE @ColumnNameAndData
SET [hex_value]
=
0xFFFE
+ SUBSTRING([hex_value],
9
, LEN([hex_value]))
--,[Update]=[Update]+
1
WHERE [system_type_id]
=
241
CREATE TABLE [#temp_Data]
(
[FieldName] VARCHAR(MAX) ,
[FieldValue] NVARCHAR(MAX) ,
[Rowlogcontents] VARBINARY(
8000
) ,
[Row ID] INT
)
INSERT INTO #temp_Data
SELECT NAME ,
CASE WHEN system_type_id IN (
231
,
239
)
THEN LTRIM(RTRIM(CONVERT(NVARCHAR(MAX), hex_Value)))
--
NVARCHAR ,NCHAR
WHEN system_type_id IN (
167
,
175
)
THEN LTRIM(RTRIM(CONVERT(VARCHAR(MAX), hex_Value)))
--
VARCHAR,CHAR
WHEN system_type_id IN (
35
)
THEN LTRIM(RTRIM(CONVERT(VARCHAR(MAX), hex_Value)))
--
Text
WHEN system_type_id IN (
99
)
THEN LTRIM(RTRIM(CONVERT(NVARCHAR(MAX), hex_Value)))
--
nText
WHEN system_type_id
=
48
THEN CONVERT(VARCHAR(MAX), CONVERT(TINYINT, CONVERT(BINARY(
1
), REVERSE(hex_Value)))) --
TINY INTEGER
WHEN system_type_id
=
52
THEN CONVERT(VARCHAR(MAX), CONVERT(SMALLINT, CONVERT(BINARY(
2
), REVERSE(hex_Value)))) --
SMALL INTEGER
WHEN system_type_id
=
56
THEN CONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(
4
), REVERSE(hex_Value)))) --
INTEGER
WHEN system_type_id
=
127
THEN CONVERT(VARCHAR(MAX), CONVERT(BIGINT, CONVERT(BINARY(
8
), REVERSE(hex_Value))))--
BIG INTEGER
WHEN system_type_id
=
61
THEN CONVERT(VARCHAR(MAX), CONVERT(DATETIME, CONVERT(VARBINARY(
8000
), REVERSE(hex_Value))),
100
) --
DATETIME
WHEN system_type_id
=
58
THEN CONVERT(VARCHAR(MAX), CONVERT(SMALLDATETIME, CONVERT(VARBINARY(
8000
), REVERSE(hex_Value))),
100
) --
SMALL DATETIME
WHEN system_type_id
=
108
THEN CONVERT(VARCHAR(MAX), CONVERT(NUMERIC(
38
,
20
), CONVERT(VARBINARY, CONVERT(VARBINARY(
1
), xprec)
+ CONVERT(VARBINARY(
1
), xscale))
+ CONVERT(VARBINARY(
1
),
0
) + hex_Value)) ---
NUMERIC
WHEN system_type_id
=
106
THEN CONVERT(VARCHAR(MAX), CONVERT(DECIMAL(
38
,
20
), CONVERT(VARBINARY, CONVERT(VARBINARY(
1
), xprec)
+ CONVERT(VARBINARY(
1
), xscale))
+ CONVERT(VARBINARY(
1
),
0
) + hex_Value)) ---
DECIMAL
WHEN system_type_id IN (
60
,
122
)
THEN CONVERT(VARCHAR(MAX), CONVERT(MONEY, CONVERT(VARBINARY(
8000
), REVERSE(hex_Value))),
2
) --
MONEY,SMALLMONEY
WHEN system_type_id
=
104
THEN CONVERT(VARCHAR(MAX), CONVERT (BIT, CONVERT(BINARY(
1
), hex_Value)
%
2
)) --
BIT
WHEN system_type_id
=
62
THEN RTRIM(LTRIM(STR(CONVERT(FLOAT, SIGN(CAST(CONVERT(VARBINARY(
8000
), REVERSE(hex_Value)) AS BIGINT))
* (
1.0
+ ( CAST(CONVERT(VARBINARY(
8000
), REVERSE(hex_Value)) AS BIGINT)
&
0x000FFFFFFFFFFFFF
)
* POWER(CAST(
2
AS FLOAT),
-
52
) )
* POWER(CAST(
2
AS FLOAT),
( ( CAST(CONVERT(VARBINARY(
8000
), REVERSE(hex_Value)) AS BIGINT)
&
0x7ff0000000000000
)
/ EXP(
52
* LOG(
2
))
-
1023
))),
53
,
LEN(hex_Value))))
---
FLOAT
WHEN system_type_id
=
59
THEN LEFT(LTRIM(STR(CAST(SIGN(CAST(CONVERT(VARBINARY(
8000
), REVERSE(hex_Value)) AS BIGINT))
* (
1.0
+ ( CAST(CONVERT(VARBINARY(
8000
), REVERSE(hex_Value)) AS BIGINT)
&
0x007FFFFF
)
* POWER(CAST(
2
AS REAL), -
23
) )
* POWER(CAST(
2
AS REAL),
( ( ( CAST(CONVERT(VARBINARY(
8000
), REVERSE(hex_Value)) AS INT) )
&
0x7f800000
)
/ EXP(
23
* LOG(
2
))
-
127
)) AS REAL),
23
,
23
)),
8
) --
Real
WHEN system_type_id IN (
165
,
173
)
THEN ( CASE WHEN CHARINDEX(0x,
CAST(
''
AS XML).value(
'
xs:hexBinary(sql:column("hex_Value"))
'
,
'
VARBINARY(8000)
'
)) =
0
THEN
'
0x
'
ELSE
''
END )
+ CAST(
''
AS XML).value(
'
xs:hexBinary(sql:column("hex_Value"))
'
,
'
varchar(max)
'
) --
BINARY,VARBINARY
WHEN system_type_id
=
34
THEN ( CASE WHEN CHARINDEX(0x,
CAST(
''
AS XML).value(
'
xs:hexBinary(sql:column("hex_Value"))
'
,
'
VARBINARY(8000)
'
)) =
0
THEN
'
0x
'
ELSE
''
END )
+ CAST(
''
AS XML).value(
'
xs:hexBinary(sql:column("hex_Value"))
'
,
'
varchar(max)
'
) --
IMAGE
WHEN system_type_id
=
36
THEN CONVERT(VARCHAR(MAX), CONVERT(UNIQUEIDENTIFIER, hex_Value))
--
UNIQUEIDENTIFIER
WHEN system_type_id
=
231
THEN CONVERT(VARCHAR(MAX), CONVERT(SYSNAME, hex_Value))
--
SYSNAME
WHEN system_type_id
=
241
THEN CONVERT(VARCHAR(MAX), CONVERT(XML, hex_Value))
--
XML
WHEN system_type_id
=
189
THEN ( CASE WHEN CHARINDEX(0x,
CAST(
''
AS XML).value(
'
xs:hexBinary(sql:column("hex_Value"))
'
,
'
VARBINARY(8000)
'
)) =
0
THEN
'
0x
'
ELSE
''
END )
+ CAST(
''
AS XML).value(
'
xs:hexBinary(sql:column("hex_Value"))
'
,
'
varchar(max)
'
) --
TIMESTAMP
WHEN system_type_id
=
98
THEN ( CASE WHEN CONVERT(INT, SUBSTRING(hex_Value,
1
,
1
)) =
56
THEN CONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(
4
), REVERSE(SUBSTRING(hex_Value,
3
,
LEN(hex_Value))))))
--
INTEGER
WHEN CONVERT(INT, SUBSTRING(hex_Value,
1
,
1
)) =
108
THEN CONVERT(VARCHAR(MAX), CONVERT(NUMERIC(
38
,
20
), CONVERT(VARBINARY(
1
), SUBSTRING(hex_Value,
3
,
1
))
+ CONVERT(VARBINARY(
1
), SUBSTRING(hex_Value,
4
,
1
))
+ CONVERT(VARBINARY(
1
),
0
)
+ SUBSTRING(hex_Value,
5
,
LEN(hex_Value))))
---
NUMERIC
WHEN CONVERT(INT, SUBSTRING(hex_Value,
1
,
1
)) =
167
THEN LTRIM(RTRIM(CONVERT(VARCHAR(MAX), SUBSTRING(hex_Value,
9
,
LEN(hex_Value)))))
--
VARCHAR,CHAR
WHEN CONVERT(INT, SUBSTRING(hex_Value,
1
,
1
)) =
36
THEN CONVERT(VARCHAR(MAX), CONVERT(UNIQUEIDENTIFIER, SUBSTRING(( hex_Value ),
3
,
20
))) --
UNIQUEIDENTIFIER
WHEN CONVERT(INT, SUBSTRING(hex_Value,
1
,
1
)) =
61
THEN CONVERT(VARCHAR(MAX), CONVERT(DATETIME, CONVERT(VARBINARY(
8000
), REVERSE(SUBSTRING(hex_Value,
3
,
LEN(hex_Value))))),
100
) --
DATETIME
WHEN CONVERT(INT, SUBSTRING(hex_Value,
1
,
1
)) =
165
THEN
'
0x
'
+
SUBSTRING(( CASE WHEN CHARINDEX(0x,
CAST(
''
AS XML).value(
'
xs:hexBinary(sql:column("hex_Value"))
'
,
'
VARBINARY(8000)
'
)) =
0
THEN
'
0x
'
ELSE
''
END )
+ CAST(
''
AS XML).value(
'
xs:hexBinary(sql:column("hex_Value"))
'
,
'
varchar(max)
'
),
11
, LEN(hex_Value)) --
BINARY,VARBINARY
END )
END AS FieldValue ,
[Rowlogcontents] ,
[Row ID]
FROM @ColumnNameAndData
ORDER BY nullbit
--Create the column name
in
the same order to
do
pivot table.
DECLARE @FieldName VARCHAR(MAX)
SET @FieldName
= STUFF(( SELECT
'
,
'
+
CAST(QUOTENAME([Name]) AS VARCHAR(MAX))
FROM syscolumns
WHERE id
= OBJECT_ID(
''
+
@SchemaName_n_TableName
+
''
)
FOR
XML PATH(
''
)
),
1
,
1
,
''
)
--Finally did pivot table and
get
the data back
in
the same format.
SET @sql
=
'
SELECT
'
+
@FieldName
+
'
FROM #temp_Data PIVOT (Min([FieldValue]) FOR FieldName IN (
'
+ @FieldName +
'
)) AS pvt
'
EXEC sp_executesql @sql
GO
---执行存储过程两个参数(数据库名,表名)
EXEC Recover_Deleted_Data_Proc
'
数据库名称
'
,
'
dbo.tableName
'--表名前面要加dbo 不然会报错的。
--执行存储过程四个参数(数据库名称,表明,开始时间,结束时间【按照时间段来恢复】)
EXEC Recover_Deleted_Data_Proc
'
数据库名称
'
,
'
dbo.TableName
'
,
'
2014-04-23
'
,
'
2014-04-23
'--表名要加dbo。
转自http://www.cnblogs.com/lyhabc/p/3683147.html#2924733.

