public PrimaryRecord(byte[] bytes, Page page) : base(page) { short offset = 0; // Parse status bits A parseStatusBitsA(new BitArray(new [] { bytes[offset++] })); // TODO: Strategize this stuff to avoid ifs, switches & impersonation if(Type == RecordType.ForwardingStub) { // Forwarding stub only has one status byte. Remaining 8 bytes are for (PageID, FileID, Slot) FixedLengthData = bytes.Skip(1).Take(8).ToArray(); int pageID = BitConverter.ToInt32(bytes, 1); short fileID = BitConverter.ToInt16(bytes, 5); short slot = BitConverter.ToInt16(bytes, 7); var forwardPage = page.Database.GetPrimaryRecordPage(new PagePointer(fileID, pageID), CompressionContext.NoCompression); byte[] forwardedRecordBytes = forwardPage.Records[slot].RawBytes; parseStatusBitsA(new BitArray(new[] {forwardedRecordBytes[0]})); bytes = forwardedRecordBytes; // We'll impersonate the ForwardingStub record type that we originated from, this allows // the engine to distinguish BlobFragments and the records that actually reference them. Type = RecordType.ForwardingStub; } // Parse status bits B parseStatusBitsB(bytes[offset++]); // Parse fixed length size short fixedLengthSize = BitConverter.ToInt16(bytes, offset); fixedLengthSize -= 4; offset += 2; // Parse fixed length data FixedLengthData = bytes.Skip(offset).Take(fixedLengthSize).ToArray(); offset += fixedLengthSize; // Parse number of columns NumberOfColumns = BitConverter.ToInt16(bytes, offset); offset += 2; // Parse null bitmap, if present if (HasNullBitmap) offset = ParseNullBitmap(bytes, ref offset); // Parse variable length columns, if present if (HasVariableLengthColumns) ParseVariableLengthColumns(bytes, ref offset); // Save complete record raw bytes RawBytes = bytes.Take(offset).ToArray(); }
internal CompressedRecord(byte[] record, Page page) { this.record = record; this.page = page; short recordPointer = 1; parseHeader(); parseCDRegion(ref recordPointer); parseShortDataRegion(ref recordPointer); parseLongDataRegion(ref recordPointer); }
public BlobInlineRootProxy(Page page, byte[] data) : base(page) { this.data = data; // Parsed according to table 7-1 (p. 378) in [SQL Server 2008 Internals] complexColumnType = data[0]; indexLevel = BitConverter.ToInt16(data, 1); unused = data[3]; sequence = BitConverter.ToInt32(data, 4); // Technically a 6-byte long value. Low two bytes always zero, thus not stored (http://bit.ly/mdAQpm) timestamp = BitConverter.ToUInt32(data, 8) << 16; }
public TextPointerProxy(Page page, byte[] bytes) : base(page) { this.bytes = bytes; /* 16 byte LOB Textpointer: * * Bytes Content * 0-3 Timestamp (int) * 4-7 ? * 8-16 Slot pointer */ timestamp = BitConverter.ToInt32(bytes, 0); lobRootSlot = new SlotPointer(bytes.Skip(8).ToArray()); }
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(); short offset = Page.Header.Pminlen; NumberOfColumns = BitConverter.ToInt16(bytes, offset); offset += 2; if (HasNullBitmap) offset = ParseNullBitmap(bytes, ref offset); if (HasVariableLengthColumns) ParseVariableLengthColumns(bytes, ref offset); }
public TextRecord(byte[] bytes, Page page) : base(page) { short offset = 0; // Parse status bits, even though we currently ignore their values. // Only one I can currently imagine being relevant is HasVersioningInformation. parseStatusBitsA(new BitArray(new [] { bytes[offset++] })); parseStatusBitsB(bytes[offset++]); // Read the fixed length portion short fixedLengthSize = BitConverter.ToInt16(bytes, offset); fixedLengthSize -= 4; offset += 2; FixedLengthData = bytes.Skip(offset).Take(fixedLengthSize).ToArray(); offset += fixedLengthSize; // No matter the text structure, they all have a common 14 byte header parseCommonTextStructureHeader(); // Save complete record raw bytes RawBytes = bytes.Take(offset).ToArray(); }
protected DataProxy(Page page) { OriginPage = page; }