Esempio n. 1
0
        public IndexRecord(byte[] bytes, Page page)
            : base(page)
        {
            parseStatusBitsA(new BitArray(new[] { bytes[0] }));

            // Index records don't contain fixed length header - it's stored in the page header
            FixedLengthData = bytes.Skip(1).Take(Page.Header.Pminlen - 1).ToArray();

            PageId = new PagePointer(ArrayHelper.SliceArray(FixedLengthData, FixedLengthData.Length - 6, 6));

            var offset = Page.Header.Pminlen;

            NumberOfColumns = BitConverter.ToInt16(bytes, offset);
            offset         += 2;

            if (HasNullBitmap)
            {
                offset = ParseNullBitmap(bytes, ref offset);
            }

            if (HasVariableLengthColumns)
            {
                ParseVariableLengthColumns(bytes, ref offset);
            }
        }
Esempio n. 2
0
        public PageHeader(byte[] header)
        {
            if (header.Length != 96)
            {
                throw new ArgumentException("Header length must be 96.");
            }

            /*
             *      Bytes	Content
             *      -----	-------
             *      00		HeaderVersion (tinyint)
             *      01		Type (tinyint)
             *      02		TypeFlagBits (tinyint)
             *      03		Level (tinyint)
             *      04-05	FlagBits (smallint)
             *      06-07	IndexID (smallint)
             *      08-11	PreviousPageID (int)
             *      12-13	PreviousFileID (smallint)
             *      14-15	Pminlen (smallint)
             *      16-19	NextPageID (int)
             *      20-21	NextPageFileID (smallint)
             *      22-23	SlotCnt (smallint)
             *      24-27	ObjectID (int)
             *      28-29	FreeCnt (smallint)
             *      30-31	FreeData (smallint)
             *      32-35	PageID (int)
             *      36-37	FileID (smallint)
             *      38-39	ReservedCnt (smallint)
             *      40-43	Lsn1 (int)
             *      44-47	Lsn2 (int)
             *      48-49	Lsn3 (smallint)
             *      50-51	XactReserved (smallint)
             *      52-55	XdesIDPart2 (int)
             *      56-57	XdesIDPart1 (smallint)
             *      58-59	GhostRecCnt (smallint)
             *      60-63	Checksum/Tornbits (int)
             *      64-95	?
             */

            HeaderVersion = header[0];
            Type          = (PageType)header[1];
            TypeFlagBits  = header[2];
            Level         = header[3];
            FlagBits      = BitConverter.ToInt16(header, 4);
            IndexID       = BitConverter.ToInt16(header, 6);
            PreviousPage  = new PagePointer(BitConverter.ToInt16(header, 12), BitConverter.ToInt32(header, 8));
            Pminlen       = BitConverter.ToInt16(header, 14);
            NextPage      = new PagePointer(BitConverter.ToInt16(header, 20), BitConverter.ToInt32(header, 16));
            SlotCnt       = BitConverter.ToInt16(header, 22);
            ObjectID      = BitConverter.ToInt32(header, 24);
            FreeCnt       = BitConverter.ToInt16(header, 28);
            FreeData      = BitConverter.ToInt16(header, 30);
            Pointer       = new PagePointer(BitConverter.ToInt16(header, 36), BitConverter.ToInt32(header, 32));
            ReservedCnt   = BitConverter.ToInt16(header, 38);
            Lsn           = "(" + BitConverter.ToInt32(header, 40) + ":" + BitConverter.ToInt32(header, 44) + ":" + BitConverter.ToInt16(header, 48) + ")";
            XactReserved  = BitConverter.ToInt16(header, 50);
            XdesID        = "(" + BitConverter.ToInt16(header, 56) + ":" + BitConverter.ToInt32(header, 52) + ")";
            GhostRecCnt   = BitConverter.ToInt16(header, 58);
        }
Esempio n. 3
0
        public PageHeader(byte[] header)
        {
            if (header.Length != 96)
                throw new ArgumentException("Header length must be 96.");

            /*
                Bytes	Content
                -----	-------
                00		HeaderVersion (tinyint)
                01		Type (tinyint)
                02		TypeFlagBits (tinyint)
                03		Level (tinyint)
                04-05	FlagBits (smallint)
                06-07	IndexID (smallint)
                08-11	PreviousPageID (int)
                12-13	PreviousFileID (smallint)
                14-15	Pminlen (smallint)
                16-19	NextPageID (int)
                20-21	NextPageFileID (smallint)
                22-23	SlotCnt (smallint)
                24-27	ObjectID (int)
                28-29	FreeCnt (smallint)
                30-31	FreeData (smallint)
                32-35	PageID (int)
                36-37	FileID (smallint)
                38-39	ReservedCnt (smallint)
                40-43	Lsn1 (int)
                44-47	Lsn2 (int)
                48-49	Lsn3 (smallint)
                50-51	XactReserved (smallint)
                52-55	XdesIDPart2 (int)
                56-57	XdesIDPart1 (smallint)
                58-59	GhostRecCnt (smallint)
                60-63	Checksum/Tornbits (int)
                64-95	?
            */

            HeaderVersion = header[0];
            Type = (PageType)header[1];
            TypeFlagBits = header[2];
            Level = header[3];
            FlagBits = BitConverter.ToInt16(header, 4);
            IndexID = BitConverter.ToInt16(header, 6);
            PreviousPage = new PagePointer(BitConverter.ToInt16(header, 12), BitConverter.ToInt32(header, 8));
            Pminlen = BitConverter.ToInt16(header, 14);
            NextPage = new PagePointer(BitConverter.ToInt16(header, 20), BitConverter.ToInt32(header, 16));
            SlotCnt = BitConverter.ToInt16(header, 22);
            ObjectID = BitConverter.ToInt32(header, 24);
            FreeCnt = BitConverter.ToInt16(header, 28);
            FreeData = BitConverter.ToInt16(header, 30);
            Pointer = new PagePointer(BitConverter.ToInt16(header, 36), BitConverter.ToInt32(header, 32));
            ReservedCnt = BitConverter.ToInt16(header, 38);
            Lsn = "(" + BitConverter.ToInt32(header, 40) + ":" + BitConverter.ToInt32(header, 44) + ":" + BitConverter.ToInt16(header, 48) + ")";
            XactReserved = BitConverter.ToInt16(header, 50);
            XdesID = "(" + BitConverter.ToInt16(header, 56) + ":" + BitConverter.ToInt32(header, 52) + ")";
            GhostRecCnt = BitConverter.ToInt16(header, 58);
        }
Esempio n. 4
0
        public ClusteredIndexRecord(byte[] bytes, Page page)
            : base(page)
        {
            parseStatusBitsA(new BitArray(new[] { bytes[0] }));

            // Index records don't contain fixed length header - it's stored in the page header
            FixedLengthData = bytes.Skip(1).Take(Page.Header.Pminlen - 1).ToArray();

            PageId = new PagePointer(ArrayHelper.SliceArray(FixedLengthData, FixedLengthData.Length - 6, 6));
        }
Esempio n. 5
0
        private void parseHeader()
        {
            /*
             *      Bytes	Content
             *      -----	-------
             *      00-03	SequenceNumber (int)
             *      04-13	?
             *      14-15	Status (smallint)
             *      16-27	?
             *      28-31	ObjectID (int)
             *      32-33	IndexID (smallint)
             *      34		PageCount (tinyint)
             *      35		?
             *      36-39	StartPage PageID (int)
             *      40-41	StartPage FileID (smallint)
             *      42-45	Slot0 PageID (int)
             *      46-47	Slot0 FileID (smallint)
             *      48-51	Slot1 PageID (int)
             *      52-53	Slot1 FileID (smallint)
             *      54-57	Slot2 PageID (v)
             *      58-59	Slot2 FileID (smallint)
             *      60-63	Slot3 PageID (int)
             *      64-65	Slot3 FileID (smallint)
             *      66-69	Slot4 PageID (int)
             *      70-71	Slot4 FileID (smallint)
             *      72-75	Slot5 PageID (int)
             *      76-77	Slot5 FileID (smallint)
             *      78-81	Slot6 PageID (int)
             *      82-83	Slot6 FileID (smallint)
             *      84-87	Slot7 PageID (int)
             *      88-89	Slot7 FileID (smallint)
             */

            byte[] header = Records[0].FixedLengthData;

            // Read iam header
            SequenceNumber = BitConverter.ToUInt32(header, 0);
            Status         = BitConverter.ToInt16(header, 14);
            ObjectID       = BitConverter.ToInt32(header, 28);
            IndexID        = BitConverter.ToInt16(header, 32);
            PageCount      = header[34];
            StartPage      = new PagePointer(BitConverter.ToInt16(header, 40), BitConverter.ToInt32(header, 36));

            // Read single page slot allocations
            Slot0 = new PagePointer(BitConverter.ToInt16(header, 46), BitConverter.ToInt32(header, 42));
            Slot1 = new PagePointer(BitConverter.ToInt16(header, 52), BitConverter.ToInt32(header, 48));
            Slot2 = new PagePointer(BitConverter.ToInt16(header, 58), BitConverter.ToInt32(header, 54));
            Slot3 = new PagePointer(BitConverter.ToInt16(header, 64), BitConverter.ToInt32(header, 60));
            Slot4 = new PagePointer(BitConverter.ToInt16(header, 70), BitConverter.ToInt32(header, 66));
            Slot5 = new PagePointer(BitConverter.ToInt16(header, 76), BitConverter.ToInt32(header, 72));
            Slot6 = new PagePointer(BitConverter.ToInt16(header, 82), BitConverter.ToInt32(header, 78));
            Slot7 = new PagePointer(BitConverter.ToInt16(header, 88), BitConverter.ToInt32(header, 84));
        }
Esempio n. 6
0
        private void parseSysrowsets()
        {
            // Using a fixed allocation unit ID, we can look up the hobt AU and scan it
            var pageLoc = new PagePointer(
                sysallocunits
                .Where(x => x.auid == FixedSystemObjectAllocationUnits.sysrowsets)
                .Single()
                .pgfirst
                );

            sysrowsets = scanner.ScanLinkedDataPages <sysrowset>(pageLoc, CompressionContext.NoCompression).ToList();
        }
Esempio n. 7
0
        private void parseSyssingleobjrefs()
        {
            // Using a fixed object ID, we can look up the partition for sysscalartypes and scan the hobt AU from there
            long rowsetID = sysrowsets
                            .Where(x => x.idmajor == (int)SystemObject.syssingleobjrefs && x.idminor == 1)
                            .Single()
                            .rowsetid;

            var pageLoc = new PagePointer(
                sysallocunits
                .Where(x => x.auid == rowsetID && x.type == 1)
                .Single()
                .pgfirst
                );

            syssingleobjrefs = scanner.ScanLinkedDataPages <syssingleobjref>(pageLoc, CompressionContext.NoCompression).ToList();
        }
Esempio n. 8
0
        internal static RecordEntityParser CreateEntityParserForPage(PagePointer loc, CompressionContext compression, Database database)
        {
            switch (compression.CompressionLevel)
            {
                case CompressionLevel.Page:
                    throw new NotImplementedException("Page compression not yet supported.");

                case CompressionLevel.Row:
                    return new CompressedRecordEntityParser(database.GetCompressedRecordPage(loc, compression));

                case CompressionLevel.None:
                    return new PrimaryRecordEntityParser(database.GetPrimaryRecordPage(loc, compression), compression);

                default:
                    throw new ArgumentException("Unsupported compression level: " + compression.CompressionLevel);
            }
        }
Esempio n. 9
0
        private void parseSyscolpars()
        {
            // Using a fixed object ID, we can look up the partition for syscolpars and scan the hobt AU from there
            long rowsetID = SysRowsets
                            .Where(x => x.idmajor == (int)SystemObject.syscolpars && x.idminor == 1)
                            .Single()
                            .rowsetid;

            var pageLoc = new PagePointer(
                SysAllocUnits
                .Where(x => x.auid == rowsetID && x.type == 1)
                .Single()
                .pgfirst
                );

            SysColPars = _scanner.ScanLinkedDataPages <syscolpar>(pageLoc, CompressionContext.NoCompression).ToList();
        }
        internal static RecordEntityParser CreateEntityParserForPage(PagePointer loc, CompressionContext compression, Database database)
        {
            switch (compression.CompressionLevel)
            {
            case CompressionLevel.Page:
                throw new NotImplementedException("Page compression not yet supported.");

            case CompressionLevel.Row:
                return(new CompressedRecordEntityParser(database.GetCompressedRecordPage(loc, compression)));

            case CompressionLevel.None:
                return(new PrimaryRecordEntityParser(database.GetPrimaryRecordPage(loc, compression), compression));

            default:
                throw new ArgumentException("Unsupported compression level: " + compression.CompressionLevel);
            }
        }
Esempio n. 11
0
        private void parseBootRecord()
        {
            /*
             *      Bytes		Content
             *      -----		-------
             *      0-1			Version (smallint)
             *      2-3			CreateVersion (smallint)
             *      4-31		?
             *      32-35		Status (int)
             *      36-39		NextID (int)
             *      40-47		?
             *      48-303		DatabaseName (nchar(128))
             *      304-307		?
             *      308-309		DBID (smallint)
             *      310-311		?
             *      312-319		MaxDBTimeStamp (bigint)
             *      320-383		?
             * 384-388     CollationId(long)
             * 389-511     ?
             *      512-515		FirstSysIndexes PageID (int)
             *      516-517		FirstSysIndexes FileID (smallint)
             *      518-1440	?
             */

            byte[] bootRecord = Records[0].FixedLengthData;

            Version       = BitConverter.ToInt16(bootRecord, 0);
            CreateVersion = BitConverter.ToInt16(bootRecord, 2);
            Status        = BitConverter.ToInt32(bootRecord, 32);
            NextID        = BitConverter.ToInt32(bootRecord, 36);

            // Truncate name at first 0x2020 char
            DatabaseName = Encoding.Unicode.GetString(bootRecord, 48, 256);
            if (DatabaseName.IndexOf('†') > 0)
            {
                DatabaseName = DatabaseName.Substring(0, DatabaseName.IndexOf('†'));
            }

            DBID            = BitConverter.ToInt16(bootRecord, 308);
            MaxDBTimeStamp  = BitConverter.ToInt64(bootRecord, 312);
            CollationId     = BitConverter.ToInt64(bootRecord, 384);
            FirstSysIndexes = new PagePointer(BitConverter.ToInt16(bootRecord, 516), BitConverter.ToInt32(bootRecord, 512));
        }
Esempio n. 12
0
        public string CreateRestoreScriptWithRollback(string connectionString, PagePointer pagePointer)
        {
            using (var connection = new SqlConnection(connectionString))
            {
                connection.Open();

                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "DBCC READPAGE (@dbName, @fileId, @pageId, 'V8192', 1)";
                    command.Parameters.AddWithValue("@dbName", connection.Database);
                    command.Parameters.AddWithValue("@fileId", pagePointer.FileID);
                    command.Parameters.AddWithValue("@pageId", pagePointer.PageID);

                    var reader = command.ExecuteReader();

                    reader.Read();

                    var pageBytes = (byte[])reader["ValueDump"];

                    var backupPage = _database.GetPage(pagePointer).RawBytes;

                    var rolloutScript =
                        "-- PAGE UPDATE SCRIPT\r\n\r\n" +
                        $"DBCC WRITEPAGE('{connection.Database}', {pagePointer.FileID}, {pagePointer.PageID}, 0, 8000, 0x{BitConverter.ToString(backupPage.Take(8000).ToArray()).Replace("-", string.Empty)}, 1);\r\n" +
                        $"DBCC WRITEPAGE('{connection.Database}', {pagePointer.FileID}, {pagePointer.PageID}, 8000, 192, 0x{BitConverter.ToString(backupPage.Skip(8000).ToArray()).Replace("-", string.Empty)}, 1);";

                    var rollBackScript =
                        "-- ROLLBACK SCRIPT\r\n\r\n" +
                        $"-- DBCC WRITEPAGE('{connection.Database}', {pagePointer.FileID}, {pagePointer.PageID}, 0, 8000, 0x{BitConverter.ToString(pageBytes.Take(8000).ToArray()).Replace("-", string.Empty)}, 1);\r\n" +
                        $"-- DBCC WRITEPAGE('{connection.Database}', {pagePointer.FileID}, {pagePointer.PageID}, 8000, 192, 0x{BitConverter.ToString(pageBytes.Skip(8000).ToArray()).Replace("-", string.Empty)}, 1);";


                    var resultScript =
                        $"\r\nUSE [{connection.Database}]\r\nGO\r\nALTER DATABASE [{connection.Database}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;\r\nGO\r\n" +
                        rolloutScript + "\r\n\r\n" + rollBackScript +
                        $"\r\n\r\nALTER DATABASE [{connection.Database}] SET MULTI_USER\r\nGO";
                    return(resultScript);
                }
            }
        }
Esempio n. 13
0
 public static PagePointer GetGamPointerForPage(PagePointer loc)
 {
     // First gam page is at index 2 and every 511232 pages hereafter
     return(new PagePointer(loc.FileID, Math.Max(loc.PageID / 511232 * 511232, 2)));
 }
Esempio n. 14
0
        private void parseBootRecord()
        {
            /*
                Bytes		Content
                -----		-------
                0-1			Version (smallint)
                2-3			CreateVersion (smallint)
                4-31		?
                32-35		Status (int)
                36-39		NextID (int)
                40-47		?
                48-303		DatabaseName (nchar(128))
                304-307		?
                308-309		DBID (smallint)
                310-311		?
                312-319		MaxDBTimeStamp (bigint)
                320-511		?
                512-515		FirstSysIndexes PageID (int)
                516-517		FirstSysIndexes FileID (smallint)
                518-1440	?
            */

            byte[] bootRecord = Records[0].FixedLengthData;

            Version = BitConverter.ToInt16(bootRecord, 0);
            CreateVersion = BitConverter.ToInt16(bootRecord, 2);
            Status = BitConverter.ToInt32(bootRecord, 32);
            NextID = BitConverter.ToInt32(bootRecord, 36);

            // Truncate name at first 0x2020 char
            DatabaseName = Encoding.Unicode.GetString(bootRecord, 48, 256);
            if (DatabaseName.IndexOf('†') > 0)
                DatabaseName = DatabaseName.Substring(0, DatabaseName.IndexOf('†'));

            DBID = BitConverter.ToInt16(bootRecord, 308);
            MaxDBTimeStamp = BitConverter.ToInt64(bootRecord, 312);
            FirstSysIndexes = new PagePointer(BitConverter.ToInt16(bootRecord, 516), BitConverter.ToInt32(bootRecord, 512));
        }
Esempio n. 15
0
 public static PagePointer GetSgamPointerForPage(PagePointer loc)
 {
     // First gam page is at index 3 and every 511232 pages hereafter
     return new PagePointer(loc.FileID, Math.Max(loc.PageID / 511232 * 511232 + 1, 3));
 }
Esempio n. 16
0
 public static PagePointer GetPfsPointerForPage(PagePointer loc)
 {
     // First pfs page is at index 1 and every 8088 pages hereafter
     return(new PagePointer(loc.FileID, Math.Max(loc.PageID / 8088 * 8088, 1)));
 }
Esempio n. 17
0
 public static PagePointer GetPfsPointerForPage(PagePointer loc)
 {
     // First pfs page is at index 1 and every 8088 pages hereafter
     return new PagePointer(loc.FileID, Math.Max(loc.PageID / 8088 * 8088, 1));
 }
Esempio n. 18
0
        private void parseHeader()
        {
            /*
                Bytes	Content
                -----	-------
                00-03	SequenceNumber (int)
                04-13	?
                14-15	Status (smallint)
                16-27	?
                28-31	ObjectID (int)
                32-33	IndexID (smallint)
                34		PageCount (tinyint)
                35		?
                36-39	StartPage PageID (int)
                40-41	StartPage FileID (smallint)
                42-45	Slot0 PageID (int)
                46-47	Slot0 FileID (smallint)
                48-51	Slot1 PageID (int)
                52-53	Slot1 FileID (smallint)
                54-57	Slot2 PageID (v)
                58-59	Slot2 FileID (smallint)
                60-63	Slot3 PageID (int)
                64-65	Slot3 FileID (smallint)
                66-69	Slot4 PageID (int)
                70-71	Slot4 FileID (smallint)
                72-75	Slot5 PageID (int)
                76-77	Slot5 FileID (smallint)
                78-81	Slot6 PageID (int)
                82-83	Slot6 FileID (smallint)
                84-87	Slot7 PageID (int)
                88-89	Slot7 FileID (smallint)
            */

            byte[] header = Records[0].FixedLengthData;

            // Read iam header
            SequenceNumber = BitConverter.ToUInt32(header, 0);
            Status = BitConverter.ToInt16(header, 14);
            ObjectID = BitConverter.ToInt32(header, 28);
            IndexID = BitConverter.ToInt16(header, 32);
            PageCount = header[34];
            StartPage = new PagePointer(BitConverter.ToInt16(header, 40), BitConverter.ToInt32(header, 36));

            // Read single page slot allocations
            Slot0 = new PagePointer(BitConverter.ToInt16(header, 46), BitConverter.ToInt32(header, 42));
            Slot1 = new PagePointer(BitConverter.ToInt16(header, 52), BitConverter.ToInt32(header, 48));
            Slot2 = new PagePointer(BitConverter.ToInt16(header, 58), BitConverter.ToInt32(header, 54));
            Slot3 = new PagePointer(BitConverter.ToInt16(header, 64), BitConverter.ToInt32(header, 60));
            Slot4 = new PagePointer(BitConverter.ToInt16(header, 70), BitConverter.ToInt32(header, 66));
            Slot5 = new PagePointer(BitConverter.ToInt16(header, 76), BitConverter.ToInt32(header, 72));
            Slot6 = new PagePointer(BitConverter.ToInt16(header, 82), BitConverter.ToInt32(header, 78));
            Slot7 = new PagePointer(BitConverter.ToInt16(header, 88), BitConverter.ToInt32(header, 84));
        }