// Location is the Location this page starts at func (p Page) Location() Location { if p.Is91() { return LocationFromUint32s(uint32(pg.LUint(p.bs[8:12])), uint32(pg.LUint(p.bs[12:16]))) } return LocationFromUint32s(uint32(pg.LUint(p.bs[12:16])), uint32(pg.LUint(p.bs[8:12]))) }
// Previous is the location of the record that preceeds this one func (r RecordHeader) Previous() Location { switch r.version { case 0xD066: return LocationFromUint32s(uint32(pg.LUint(r.bs[4:8])), uint32(pg.LUint(r.bs[8:12]))) case 0xD07E: return LocationFromUint32s(uint32(pg.LUint(r.bs[20:24])), uint32(pg.LUint(r.bs[16:20]))) } return Location{} }
// Crc is the crc of the record func (r RecordHeader) Crc() uint32 { switch r.version { case 0xD066: return uint32(pg.LUint(r.bs[0:4])) case 0xD07E: return uint32(pg.LUint(r.bs[24:28])) } return 0 }
// ResourceManagerID is the ID of the resource manager that created this record func (r RecordHeader) ResourceManagerID() uint8 { switch r.version { case 0xD066: return uint8(pg.LUint(r.bs[25:26])) case 0xD07E: return uint8(pg.LUint(r.bs[13:14])) } return 0 }
// Info contains resource manager specific data func (r RecordHeader) Info() uint8 { switch r.version { case 0xD066: return uint8(pg.LUint(r.bs[24:25])) case 0xD07E: return uint8(pg.LUint(r.bs[12:13])) } return 0 }
// Length is the length of resource manager specific data after the header func (r RecordHeader) Length() uint32 { switch r.version { case 0xD066: return uint32(pg.LUint(r.bs[20:24])) case 0xD07E: return uint32(pg.LUint(r.bs[8:12])) } return 0 }
// TotalLength is the length of the body after the header but before the next record func (r RecordHeader) TotalLength() uint32 { switch r.version { case 0xD066: return uint32(pg.LUint(r.bs[16:20])) case 0xD07E: return uint32(pg.LUint(r.bs[0:4])) } return 0 }
// TransactionID is the transaction that this record is apart of func (r RecordHeader) TransactionID() uint32 { switch r.version { case 0xD066: return uint32(pg.LUint(r.bs[12:16])) case 0xD07E: return uint32(pg.LUint(r.bs[4:8])) } return 0 }
// ToOffset is item number of the new version of this tuple func (d UpdateData) ToOffset() uint16 { switch d.version { case 0xD066: return uint16(pg.LUint(d.bs[24:26])) case 0xD07E: return uint16(pg.LUint(d.bs[32:34])) } return 0 }
// BlockSize is the size of a page in a WAL file func (p Page) BlockSize() uint32 { if p.IsLong() { return uint32(pg.LUint(p.bs[28:32])) } return 0 }
// SegmentSize is the size in bytes of a single WAL file func (p Page) SegmentSize() uint32 { if p.IsLong() { return uint32(pg.LUint(p.bs[24:28])) } return 0 }
// SystemID can be used to determine if a page was written by a particular server func (p Page) SystemID() uint64 { if p.IsLong() { return uint64(pg.LUint(p.bs[16:24])) } return 0 }
func parseMultiInsertData(isInit bool, d []byte) (multiInserts []HeapData) { const XlogHeapInitPage = 128 var ( tablespaceID = uint32(pg.LUint(d[0:4])) databaseID = uint32(pg.LUint(d[4:8])) relationID = uint32(pg.LUint(d[8:12])) toBlock = uint32(pg.LUint(d[12:16])) flags = d[16] ntuples = uint16(pg.LUint(d[18:20])) ) isInit = isInit || flags&XlogHeapInitPage > 0 for i := uint16(0); i < ntuples; i++ { if isInit { multiInserts = append(multiInserts, MultiInsertData{tablespaceID, databaseID, relationID, toBlock, i + 1}) } else { var ( start = i*2 + 20 end = start + 2 toOffset = uint16(pg.LUint(d[start:end])) ) multiInserts = append(multiInserts, MultiInsertData{tablespaceID, databaseID, relationID, toBlock, toOffset}) } } return }
// Continuation will return the bytes of a continuation of the previous record's body if present on the page func (p Page) Continuation() []byte { if p.IsCont() { var contStart, contEnd uint64 if p.Is94() { contStart = p.HeaderLength() contEnd = contStart + pg.LUint(p.bs[16:20]) } else { sizeOffset := p.HeaderLength() contStart = sizeOffset + 4 contEnd = contStart + pg.LUint(p.bs[sizeOffset:contStart]) } maxContEnd := uint64(len(p.bs)) if contEnd > maxContEnd { contEnd = maxContEnd } return p.bs[contStart:contEnd] } return nil }
// Continuation will return the bytes of a continuation of the previous record's body if present on the page func (p Page) Continuation() []byte { if p.IsCont() { sizeOffset := p.HeaderLength() contStart := sizeOffset + 4 contEnd := contStart + uint64(pg.LUint(p.bs[sizeOffset:contStart])) maxContEnd := uint64(len(p.bs)) if contEnd > maxContEnd { contEnd = maxContEnd } return p.bs[contStart:contEnd] } return nil }
// DatabaseID is the id of the database this tuple is found in func (d InsertData) DatabaseID() uint32 { return uint32(pg.LUint(d[4:8])) }
// TablespaceID is the id of the tablespace this tuple is found in func (d InsertData) TablespaceID() uint32 { return uint32(pg.LUint(d[0:4])) }
func readBlockID(bs []byte) uint32 { return (uint32(pg.LUint(bs[0:2])) << 16) + uint32(pg.LUint(bs[2:4])) }
// TimelineID is the timeline this page is found on func (p Page) TimelineID() uint32 { return uint32(pg.LUint(p.bs[4:8])) }
// RelationID is the id of the relation this tuple is found in func (d UpdateData) RelationID() uint32 { return uint32(pg.LUint(d.bs[8:12])) }
// TablespaceID is the id of the tablespace this tuple is found in func (d UpdateData) TablespaceID() uint32 { return uint32(pg.LUint(d.bs[0:4])) }
// TablespaceID is the id of the tablespace this tuple is found in func (d DeleteData) TablespaceID() uint32 { return uint32(pg.LUint(d[0:4])) }
// RelationID is the id of the relation this tuple is found in func (d InsertData) RelationID() uint32 { return uint32(pg.LUint(d[8:12])) }
// DatabaseID is the id of the database this tuple is found in func (d DeleteData) DatabaseID() uint32 { return uint32(pg.LUint(d[4:8])) }
// ToOffset is the item number where this tuple now resides func (d InsertData) ToOffset() uint16 { return uint16(pg.LUint(d[16:18])) }
// RelationID is the id of the relation this tuple is found in func (d DeleteData) RelationID() uint32 { return uint32(pg.LUint(d[8:12])) }
// DatabaseID is the id of the database this tuple is found in func (d UpdateData) DatabaseID() uint32 { return uint32(pg.LUint(d.bs[4:8])) }
// FromOffset is the item number where this tuple previously resided func (d DeleteData) FromOffset() uint16 { return uint16(pg.LUint(d[16:18])) }
// FromOffset is the item number of the old version of this tuple func (d UpdateData) FromOffset() uint16 { return uint16(pg.LUint(d.bs[16:18])) }
// Info can be used to determine if a page header is long (bit 2 is set) or if it contains a continuation (bit 1 is set) func (p Page) Info() uint16 { return uint16(pg.LUint(p.bs[2:4])) }