SQLite3 database file: Go parsing library

SQLite3 is a popular serverless SQL engine, implemented as a library to be used within other applications. It keeps its databases as regular disk files.

Every database file is segmented into pages. First page (starting at the very beginning) is special: it contains a file-global header which specifies some data relevant to proper parsing (i.e. format versions, size of page, etc). After the header, normal contents of the first page follow.

Each page would be of some type, and generally, they would be reached via the links starting from the first page. First page type (root_page) is always "btree_page".

File extension

["sqlite", "db", "db3", "sqlite3"]

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.9

References

This page hosts a formal specification of SQLite3 database file using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Go source code to parse SQLite3 database file

sqlite3.go

// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.

import (
	"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
	"bytes"
	"io"
)


/**
 * SQLite3 is a popular serverless SQL engine, implemented as a library
 * to be used within other applications. It keeps its databases as
 * regular disk files.
 * 
 * Every database file is segmented into pages. First page (starting at
 * the very beginning) is special: it contains a file-global header
 * which specifies some data relevant to proper parsing (i.e. format
 * versions, size of page, etc). After the header, normal contents of
 * the first page follow.
 * 
 * Each page would be of some type, and generally, they would be
 * reached via the links starting from the first page. First page type
 * (`root_page`) is always "btree_page".
 * @see <a href="https://www.sqlite.org/fileformat.html">Source</a>
 */

type Sqlite3_Versions int
const (
	Sqlite3_Versions__Legacy Sqlite3_Versions = 1
	Sqlite3_Versions__Wal Sqlite3_Versions = 2
)

type Sqlite3_Encodings int
const (
	Sqlite3_Encodings__Utf8 Sqlite3_Encodings = 1
	Sqlite3_Encodings__Utf16le Sqlite3_Encodings = 2
	Sqlite3_Encodings__Utf16be Sqlite3_Encodings = 3
)
type Sqlite3 struct {
	Magic []byte
	LenPageMod uint16
	WriteVersion Sqlite3_Versions
	ReadVersion Sqlite3_Versions
	ReservedSpace uint8
	MaxPayloadFrac uint8
	MinPayloadFrac uint8
	LeafPayloadFrac uint8
	FileChangeCounter uint32
	NumPages uint32
	FirstFreelistTrunkPage uint32
	NumFreelistPages uint32
	SchemaCookie uint32
	SchemaFormat uint32
	DefPageCacheSize uint32
	LargestRootPage uint32
	TextEncoding Sqlite3_Encodings
	UserVersion uint32
	IsIncrementalVacuum uint32
	ApplicationId uint32
	Reserved []byte
	VersionValidFor uint32
	SqliteVersionNumber uint32
	RootPage *Sqlite3_BtreePage
	_io *kaitai.Stream
	_root *Sqlite3
	_parent interface{}
	_f_lenPage bool
	lenPage int
}
func NewSqlite3() *Sqlite3 {
	return &Sqlite3{
	}
}

func (this *Sqlite3) Read(io *kaitai.Stream, parent interface{}, root *Sqlite3) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp1, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp1 = tmp1
	this.Magic = tmp1
	if !(bytes.Equal(this.Magic, []uint8{83, 81, 76, 105, 116, 101, 32, 102, 111, 114, 109, 97, 116, 32, 51, 0})) {
		return kaitai.NewValidationNotEqualError([]uint8{83, 81, 76, 105, 116, 101, 32, 102, 111, 114, 109, 97, 116, 32, 51, 0}, this.Magic, this._io, "/seq/0")
	}
	tmp2, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.LenPageMod = uint16(tmp2)
	tmp3, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.WriteVersion = Sqlite3_Versions(tmp3)
	tmp4, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.ReadVersion = Sqlite3_Versions(tmp4)
	tmp5, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.ReservedSpace = tmp5
	tmp6, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.MaxPayloadFrac = tmp6
	tmp7, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.MinPayloadFrac = tmp7
	tmp8, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LeafPayloadFrac = tmp8
	tmp9, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.FileChangeCounter = uint32(tmp9)
	tmp10, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumPages = uint32(tmp10)
	tmp11, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.FirstFreelistTrunkPage = uint32(tmp11)
	tmp12, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumFreelistPages = uint32(tmp12)
	tmp13, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.SchemaCookie = uint32(tmp13)
	tmp14, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.SchemaFormat = uint32(tmp14)
	tmp15, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.DefPageCacheSize = uint32(tmp15)
	tmp16, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LargestRootPage = uint32(tmp16)
	tmp17, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.TextEncoding = Sqlite3_Encodings(tmp17)
	tmp18, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.UserVersion = uint32(tmp18)
	tmp19, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.IsIncrementalVacuum = uint32(tmp19)
	tmp20, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.ApplicationId = uint32(tmp20)
	tmp21, err := this._io.ReadBytes(int(20))
	if err != nil {
		return err
	}
	tmp21 = tmp21
	this.Reserved = tmp21
	tmp22, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.VersionValidFor = uint32(tmp22)
	tmp23, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.SqliteVersionNumber = uint32(tmp23)
	tmp24 := NewSqlite3_BtreePage()
	err = tmp24.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.RootPage = tmp24
	return err
}
func (this *Sqlite3) LenPage() (v int, err error) {
	if (this._f_lenPage) {
		return this.lenPage, nil
	}
	var tmp25 int;
	if (this.LenPageMod == 1) {
		tmp25 = 65536
	} else {
		tmp25 = this.LenPageMod
	}
	this.lenPage = int(tmp25)
	this._f_lenPage = true
	return this.lenPage, nil
}

/**
 * The database page size in bytes. Must be a power of two between
 * 512 and 32768 inclusive, or the value 1 representing a page size
 * of 65536.
 */

/**
 * Bytes of unused "reserved" space at the end of each page. Usually 0.
 */

/**
 * Maximum embedded payload fraction. Must be 64.
 */

/**
 * Minimum embedded payload fraction. Must be 32.
 */

/**
 * Leaf payload fraction. Must be 32.
 */

/**
 * Size of the database file in pages. The "in-header database size".
 */

/**
 * Page number of the first freelist trunk page.
 */

/**
 * Total number of freelist pages.
 */

/**
 * The schema format number. Supported schema formats are 1, 2, 3, and 4.
 */

/**
 * Default page cache size.
 */

/**
 * The page number of the largest root b-tree page when in auto-vacuum or incremental-vacuum modes, or zero otherwise.
 */

/**
 * The database text encoding. A value of 1 means UTF-8. A value of 2 means UTF-16le. A value of 3 means UTF-16be.
 */

/**
 * The "user version" as read and set by the user_version pragma.
 */

/**
 * True (non-zero) for incremental-vacuum mode. False (zero) otherwise.
 */

/**
 * The "Application ID" set by PRAGMA application_id.
 */
type Sqlite3_Serial struct {
	Code *VlqBase128Be
	_io *kaitai.Stream
	_root *Sqlite3
	_parent *Sqlite3_Serials
	_f_isBlob bool
	isBlob bool
	_f_isString bool
	isString bool
	_f_lenContent bool
	lenContent int
}
func NewSqlite3_Serial() *Sqlite3_Serial {
	return &Sqlite3_Serial{
	}
}

func (this *Sqlite3_Serial) Read(io *kaitai.Stream, parent *Sqlite3_Serials, root *Sqlite3) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp26 := NewVlqBase128Be()
	err = tmp26.Read(this._io, this, nil)
	if err != nil {
		return err
	}
	this.Code = tmp26
	return err
}
func (this *Sqlite3_Serial) IsBlob() (v bool, err error) {
	if (this._f_isBlob) {
		return this.isBlob, nil
	}
	tmp27, err := this.Code.Value()
	if err != nil {
		return false, err
	}
	tmp29, err := this.Code.Value()
	if err != nil {
		return false, err
	}
	tmp28 := tmp29 % 2
	if tmp28 < 0 {
		tmp28 += 2
	}
	this.isBlob = bool( ((tmp27 >= 12) && (tmp28 == 0)) )
	this._f_isBlob = true
	return this.isBlob, nil
}
func (this *Sqlite3_Serial) IsString() (v bool, err error) {
	if (this._f_isString) {
		return this.isString, nil
	}
	tmp30, err := this.Code.Value()
	if err != nil {
		return false, err
	}
	tmp32, err := this.Code.Value()
	if err != nil {
		return false, err
	}
	tmp31 := tmp32 % 2
	if tmp31 < 0 {
		tmp31 += 2
	}
	this.isString = bool( ((tmp30 >= 13) && (tmp31 == 1)) )
	this._f_isString = true
	return this.isString, nil
}
func (this *Sqlite3_Serial) LenContent() (v int, err error) {
	if (this._f_lenContent) {
		return this.lenContent, nil
	}
	tmp33, err := this.Code.Value()
	if err != nil {
		return 0, err
	}
	if (tmp33 >= 12) {
		tmp34, err := this.Code.Value()
		if err != nil {
			return 0, err
		}
		this.lenContent = int(((tmp34 - 12) / 2))
	}
	this._f_lenContent = true
	return this.lenContent, nil
}
type Sqlite3_BtreePage struct {
	PageType uint8
	FirstFreeblock uint16
	NumCells uint16
	OfsCells uint16
	NumFragFreeBytes uint8
	RightPtr uint32
	Cells []*Sqlite3_RefCell
	_io *kaitai.Stream
	_root *Sqlite3
	_parent *Sqlite3
}
func NewSqlite3_BtreePage() *Sqlite3_BtreePage {
	return &Sqlite3_BtreePage{
	}
}

func (this *Sqlite3_BtreePage) Read(io *kaitai.Stream, parent *Sqlite3, root *Sqlite3) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp35, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.PageType = tmp35
	tmp36, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.FirstFreeblock = uint16(tmp36)
	tmp37, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.NumCells = uint16(tmp37)
	tmp38, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.OfsCells = uint16(tmp38)
	tmp39, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.NumFragFreeBytes = tmp39
	if ( ((this.PageType == 2) || (this.PageType == 5)) ) {
		tmp40, err := this._io.ReadU4be()
		if err != nil {
			return err
		}
		this.RightPtr = uint32(tmp40)
	}
	for i := 0; i < int(this.NumCells); i++ {
		_ = i
		tmp41 := NewSqlite3_RefCell()
		err = tmp41.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Cells = append(this.Cells, tmp41)
	}
	return err
}

/**
 * @see <a href="https://www.sqlite.org/fileformat.html#b_tree_pages">Source</a>
 */
type Sqlite3_CellIndexLeaf struct {
	LenPayload *VlqBase128Be
	Payload *Sqlite3_CellPayload
	_io *kaitai.Stream
	_root *Sqlite3
	_parent *Sqlite3_RefCell
	_raw_Payload []byte
}
func NewSqlite3_CellIndexLeaf() *Sqlite3_CellIndexLeaf {
	return &Sqlite3_CellIndexLeaf{
	}
}

func (this *Sqlite3_CellIndexLeaf) Read(io *kaitai.Stream, parent *Sqlite3_RefCell, root *Sqlite3) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp42 := NewVlqBase128Be()
	err = tmp42.Read(this._io, this, nil)
	if err != nil {
		return err
	}
	this.LenPayload = tmp42
	tmp43, err := this.LenPayload.Value()
	if err != nil {
		return err
	}
	tmp44, err := this._io.ReadBytes(int(tmp43))
	if err != nil {
		return err
	}
	tmp44 = tmp44
	this._raw_Payload = tmp44
	_io__raw_Payload := kaitai.NewStream(bytes.NewReader(this._raw_Payload))
	tmp45 := NewSqlite3_CellPayload()
	err = tmp45.Read(_io__raw_Payload, this, this._root)
	if err != nil {
		return err
	}
	this.Payload = tmp45
	return err
}
type Sqlite3_Serials struct {
	Entries []*Sqlite3_Serial
	_io *kaitai.Stream
	_root *Sqlite3
	_parent *Sqlite3_CellPayload
}
func NewSqlite3_Serials() *Sqlite3_Serials {
	return &Sqlite3_Serials{
	}
}

func (this *Sqlite3_Serials) Read(io *kaitai.Stream, parent *Sqlite3_CellPayload, root *Sqlite3) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 1;; i++ {
		tmp46, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp46 {
			break
		}
		tmp47 := NewSqlite3_Serial()
		err = tmp47.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Entries = append(this.Entries, tmp47)
	}
	return err
}

/**
 * @see <a href="https://www.sqlite.org/fileformat.html#b_tree_pages">Source</a>
 */
type Sqlite3_CellTableLeaf struct {
	LenPayload *VlqBase128Be
	RowId *VlqBase128Be
	Payload *Sqlite3_CellPayload
	_io *kaitai.Stream
	_root *Sqlite3
	_parent *Sqlite3_RefCell
	_raw_Payload []byte
}
func NewSqlite3_CellTableLeaf() *Sqlite3_CellTableLeaf {
	return &Sqlite3_CellTableLeaf{
	}
}

func (this *Sqlite3_CellTableLeaf) Read(io *kaitai.Stream, parent *Sqlite3_RefCell, root *Sqlite3) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp48 := NewVlqBase128Be()
	err = tmp48.Read(this._io, this, nil)
	if err != nil {
		return err
	}
	this.LenPayload = tmp48
	tmp49 := NewVlqBase128Be()
	err = tmp49.Read(this._io, this, nil)
	if err != nil {
		return err
	}
	this.RowId = tmp49
	tmp50, err := this.LenPayload.Value()
	if err != nil {
		return err
	}
	tmp51, err := this._io.ReadBytes(int(tmp50))
	if err != nil {
		return err
	}
	tmp51 = tmp51
	this._raw_Payload = tmp51
	_io__raw_Payload := kaitai.NewStream(bytes.NewReader(this._raw_Payload))
	tmp52 := NewSqlite3_CellPayload()
	err = tmp52.Read(_io__raw_Payload, this, this._root)
	if err != nil {
		return err
	}
	this.Payload = tmp52
	return err
}

/**
 * @see <a href="https://sqlite.org/fileformat2.html#record_format">Source</a>
 */
type Sqlite3_CellPayload struct {
	LenHeaderAndLen *VlqBase128Be
	ColumnSerials *Sqlite3_Serials
	ColumnContents []*Sqlite3_ColumnContent
	_io *kaitai.Stream
	_root *Sqlite3
	_parent interface{}
	_raw_ColumnSerials []byte
}
func NewSqlite3_CellPayload() *Sqlite3_CellPayload {
	return &Sqlite3_CellPayload{
	}
}

func (this *Sqlite3_CellPayload) Read(io *kaitai.Stream, parent interface{}, root *Sqlite3) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp53 := NewVlqBase128Be()
	err = tmp53.Read(this._io, this, nil)
	if err != nil {
		return err
	}
	this.LenHeaderAndLen = tmp53
	tmp54, err := this.LenHeaderAndLen.Value()
	if err != nil {
		return err
	}
	tmp55, err := this._io.ReadBytes(int((tmp54 - 1)))
	if err != nil {
		return err
	}
	tmp55 = tmp55
	this._raw_ColumnSerials = tmp55
	_io__raw_ColumnSerials := kaitai.NewStream(bytes.NewReader(this._raw_ColumnSerials))
	tmp56 := NewSqlite3_Serials()
	err = tmp56.Read(_io__raw_ColumnSerials, this, this._root)
	if err != nil {
		return err
	}
	this.ColumnSerials = tmp56
	for i := 0; i < int(len(this.ColumnSerials.Entries)); i++ {
		_ = i
		tmp57 := NewSqlite3_ColumnContent(this.ColumnSerials.Entries[i])
		err = tmp57.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.ColumnContents = append(this.ColumnContents, tmp57)
	}
	return err
}

/**
 * @see <a href="https://www.sqlite.org/fileformat.html#b_tree_pages">Source</a>
 */
type Sqlite3_CellTableInterior struct {
	LeftChildPage uint32
	RowId *VlqBase128Be
	_io *kaitai.Stream
	_root *Sqlite3
	_parent *Sqlite3_RefCell
}
func NewSqlite3_CellTableInterior() *Sqlite3_CellTableInterior {
	return &Sqlite3_CellTableInterior{
	}
}

func (this *Sqlite3_CellTableInterior) Read(io *kaitai.Stream, parent *Sqlite3_RefCell, root *Sqlite3) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp58, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LeftChildPage = uint32(tmp58)
	tmp59 := NewVlqBase128Be()
	err = tmp59.Read(this._io, this, nil)
	if err != nil {
		return err
	}
	this.RowId = tmp59
	return err
}

/**
 * @see <a href="https://www.sqlite.org/fileformat.html#b_tree_pages">Source</a>
 */
type Sqlite3_CellIndexInterior struct {
	LeftChildPage uint32
	LenPayload *VlqBase128Be
	Payload *Sqlite3_CellPayload
	_io *kaitai.Stream
	_root *Sqlite3
	_parent *Sqlite3_RefCell
	_raw_Payload []byte
}
func NewSqlite3_CellIndexInterior() *Sqlite3_CellIndexInterior {
	return &Sqlite3_CellIndexInterior{
	}
}

func (this *Sqlite3_CellIndexInterior) Read(io *kaitai.Stream, parent *Sqlite3_RefCell, root *Sqlite3) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp60, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LeftChildPage = uint32(tmp60)
	tmp61 := NewVlqBase128Be()
	err = tmp61.Read(this._io, this, nil)
	if err != nil {
		return err
	}
	this.LenPayload = tmp61
	tmp62, err := this.LenPayload.Value()
	if err != nil {
		return err
	}
	tmp63, err := this._io.ReadBytes(int(tmp62))
	if err != nil {
		return err
	}
	tmp63 = tmp63
	this._raw_Payload = tmp63
	_io__raw_Payload := kaitai.NewStream(bytes.NewReader(this._raw_Payload))
	tmp64 := NewSqlite3_CellPayload()
	err = tmp64.Read(_io__raw_Payload, this, this._root)
	if err != nil {
		return err
	}
	this.Payload = tmp64
	return err
}
type Sqlite3_ColumnContent struct {
	AsInt int
	AsFloat float64
	AsBlob []byte
	AsStr string
	SerialType *Sqlite3_Serial
	_io *kaitai.Stream
	_root *Sqlite3
	_parent *Sqlite3_CellPayload
}
func NewSqlite3_ColumnContent(serialType *Sqlite3_Serial) *Sqlite3_ColumnContent {
	return &Sqlite3_ColumnContent{
		SerialType: serialType,
	}
}

func (this *Sqlite3_ColumnContent) Read(io *kaitai.Stream, parent *Sqlite3_CellPayload, root *Sqlite3) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp65, err := this.SerialType.Code.Value()
	if err != nil {
		return err
	}
	tmp66, err := this.SerialType.Code.Value()
	if err != nil {
		return err
	}
	if ( ((tmp65 >= 1) && (tmp66 <= 6)) ) {
		tmp67, err := this.SerialType.Code.Value()
		if err != nil {
			return err
		}
		switch (tmp67) {
		case 4:
			tmp68, err := this._io.ReadU4be()
			if err != nil {
				return err
			}
			this.AsInt = tmp68
		case 6:
			tmp69, err := this._io.ReadU8be()
			if err != nil {
				return err
			}
			this.AsInt = tmp69
		case 1:
			tmp70, err := this._io.ReadU1()
			if err != nil {
				return err
			}
			this.AsInt = tmp70
		case 3:
			tmp71, err := this._io.ReadBitsIntBe(24)
			if err != nil {
				return err
			}
			this.AsInt = tmp71
		case 5:
			tmp72, err := this._io.ReadBitsIntBe(48)
			if err != nil {
				return err
			}
			this.AsInt = tmp72
		case 2:
			tmp73, err := this._io.ReadU2be()
			if err != nil {
				return err
			}
			this.AsInt = tmp73
		}
	}
	tmp74, err := this.SerialType.Code.Value()
	if err != nil {
		return err
	}
	if (tmp74 == 7) {
		tmp75, err := this._io.ReadF8be()
		if err != nil {
			return err
		}
		this.AsFloat = float64(tmp75)
	}
	tmp76, err := this.SerialType.IsBlob()
	if err != nil {
		return err
	}
	if (tmp76) {
		tmp77, err := this.SerialType.LenContent()
		if err != nil {
			return err
		}
		tmp78, err := this._io.ReadBytes(int(tmp77))
		if err != nil {
			return err
		}
		tmp78 = tmp78
		this.AsBlob = tmp78
	}
	tmp79, err := this.SerialType.LenContent()
	if err != nil {
		return err
	}
	tmp80, err := this._io.ReadBytes(int(tmp79))
	if err != nil {
		return err
	}
	tmp80 = tmp80
	this.AsStr = string(tmp80)
	return err
}
type Sqlite3_RefCell struct {
	OfsBody uint16
	_io *kaitai.Stream
	_root *Sqlite3
	_parent *Sqlite3_BtreePage
	_f_body bool
	body interface{}
}
func NewSqlite3_RefCell() *Sqlite3_RefCell {
	return &Sqlite3_RefCell{
	}
}

func (this *Sqlite3_RefCell) Read(io *kaitai.Stream, parent *Sqlite3_BtreePage, root *Sqlite3) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp81, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.OfsBody = uint16(tmp81)
	return err
}
func (this *Sqlite3_RefCell) Body() (v interface{}, err error) {
	if (this._f_body) {
		return this.body, nil
	}
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(this.OfsBody), io.SeekStart)
	if err != nil {
		return nil, err
	}
	switch (this._parent.PageType) {
	case 13:
		tmp82 := NewSqlite3_CellTableLeaf()
		err = tmp82.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.body = tmp82
	case 5:
		tmp83 := NewSqlite3_CellTableInterior()
		err = tmp83.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.body = tmp83
	case 10:
		tmp84 := NewSqlite3_CellIndexLeaf()
		err = tmp84.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.body = tmp84
	case 2:
		tmp85 := NewSqlite3_CellIndexInterior()
		err = tmp85.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.body = tmp85
	}
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	this._f_body = true
	this._f_body = true
	return this.body, nil
}