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_Encodings int
const (
	Sqlite3_Encodings__Utf8 Sqlite3_Encodings = 1
	Sqlite3_Encodings__Utf16le Sqlite3_Encodings = 2
	Sqlite3_Encodings__Utf16be Sqlite3_Encodings = 3
)
var values_Sqlite3_Encodings = map[Sqlite3_Encodings]struct{}{1: {}, 2: {}, 3: {}}
func (v Sqlite3_Encodings) isDefined() bool {
	_, ok := values_Sqlite3_Encodings[v]
	return ok
}

type Sqlite3_Versions int
const (
	Sqlite3_Versions__Legacy Sqlite3_Versions = 1
	Sqlite3_Versions__Wal Sqlite3_Versions = 2
)
var values_Sqlite3_Versions = map[Sqlite3_Versions]struct{}{1: {}, 2: {}}
func (v Sqlite3_Versions) isDefined() bool {
	_, ok := values_Sqlite3_Versions[v]
	return ok
}
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 kaitai.Struct
	_f_lenPage bool
	lenPage int
}
func NewSqlite3() *Sqlite3 {
	return &Sqlite3{
	}
}

func (this Sqlite3) IO_() *kaitai.Stream {
	return this._io
}

func (this *Sqlite3) Read(io *kaitai.Stream, parent kaitai.Struct, 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
	}
	this._f_lenPage = true
	var tmp25 int;
	if (this.LenPageMod == 1) {
		tmp25 = 65536
	} else {
		tmp25 = this.LenPageMod
	}
	this.lenPage = int(tmp25)
	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_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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp26, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.PageType = tmp26
	tmp27, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.FirstFreeblock = uint16(tmp27)
	tmp28, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.NumCells = uint16(tmp28)
	tmp29, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.OfsCells = uint16(tmp29)
	tmp30, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.NumFragFreeBytes = tmp30
	if ( ((this.PageType == 2) || (this.PageType == 5)) ) {
		tmp31, err := this._io.ReadU4be()
		if err != nil {
			return err
		}
		this.RightPtr = uint32(tmp31)
	}
	for i := 0; i < int(this.NumCells); i++ {
		_ = i
		tmp32 := NewSqlite3_RefCell()
		err = tmp32.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Cells = append(this.Cells, tmp32)
	}
	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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp33, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LeftChildPage = uint32(tmp33)
	tmp34 := NewVlqBase128Be()
	err = tmp34.Read(this._io, nil, nil)
	if err != nil {
		return err
	}
	this.LenPayload = tmp34
	tmp35, err := this.LenPayload.Value()
	if err != nil {
		return err
	}
	tmp36, err := this._io.ReadBytes(int(tmp35))
	if err != nil {
		return err
	}
	tmp36 = tmp36
	this._raw_Payload = tmp36
	_io__raw_Payload := kaitai.NewStream(bytes.NewReader(this._raw_Payload))
	tmp37 := NewSqlite3_CellPayload()
	err = tmp37.Read(_io__raw_Payload, this, this._root)
	if err != nil {
		return err
	}
	this.Payload = tmp37
	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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp38 := NewVlqBase128Be()
	err = tmp38.Read(this._io, nil, nil)
	if err != nil {
		return err
	}
	this.LenPayload = tmp38
	tmp39, err := this.LenPayload.Value()
	if err != nil {
		return err
	}
	tmp40, err := this._io.ReadBytes(int(tmp39))
	if err != nil {
		return err
	}
	tmp40 = tmp40
	this._raw_Payload = tmp40
	_io__raw_Payload := kaitai.NewStream(bytes.NewReader(this._raw_Payload))
	tmp41 := NewSqlite3_CellPayload()
	err = tmp41.Read(_io__raw_Payload, this, this._root)
	if err != nil {
		return err
	}
	this.Payload = tmp41
	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 kaitai.Struct
	_raw_ColumnSerials []byte
}
func NewSqlite3_CellPayload() *Sqlite3_CellPayload {
	return &Sqlite3_CellPayload{
	}
}

func (this Sqlite3_CellPayload) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp42 := NewVlqBase128Be()
	err = tmp42.Read(this._io, nil, nil)
	if err != nil {
		return err
	}
	this.LenHeaderAndLen = tmp42
	tmp43, err := this.LenHeaderAndLen.Value()
	if err != nil {
		return err
	}
	tmp44, err := this._io.ReadBytes(int(tmp43 - 1))
	if err != nil {
		return err
	}
	tmp44 = tmp44
	this._raw_ColumnSerials = tmp44
	_io__raw_ColumnSerials := kaitai.NewStream(bytes.NewReader(this._raw_ColumnSerials))
	tmp45 := NewSqlite3_Serials()
	err = tmp45.Read(_io__raw_ColumnSerials, this, this._root)
	if err != nil {
		return err
	}
	this.ColumnSerials = tmp45
	for i := 0; i < int(len(this.ColumnSerials.Entries)); i++ {
		_ = i
		tmp46 := NewSqlite3_ColumnContent(this.ColumnSerials.Entries[i])
		err = tmp46.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.ColumnContents = append(this.ColumnContents, tmp46)
	}
	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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp47, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LeftChildPage = uint32(tmp47)
	tmp48 := NewVlqBase128Be()
	err = tmp48.Read(this._io, nil, nil)
	if err != nil {
		return err
	}
	this.RowId = tmp48
	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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp49 := NewVlqBase128Be()
	err = tmp49.Read(this._io, nil, nil)
	if err != nil {
		return err
	}
	this.LenPayload = tmp49
	tmp50 := NewVlqBase128Be()
	err = tmp50.Read(this._io, nil, nil)
	if err != nil {
		return err
	}
	this.RowId = tmp50
	tmp51, err := this.LenPayload.Value()
	if err != nil {
		return err
	}
	tmp52, err := this._io.ReadBytes(int(tmp51))
	if err != nil {
		return err
	}
	tmp52 = tmp52
	this._raw_Payload = tmp52
	_io__raw_Payload := kaitai.NewStream(bytes.NewReader(this._raw_Payload))
	tmp53 := NewSqlite3_CellPayload()
	err = tmp53.Read(_io__raw_Payload, this, this._root)
	if err != nil {
		return err
	}
	this.Payload = tmp53
	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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp54, err := this.SerialType.Code.Value()
	if err != nil {
		return err
	}
	tmp55, err := this.SerialType.Code.Value()
	if err != nil {
		return err
	}
	if ( ((tmp54 >= 1) && (tmp55 <= 6)) ) {
		tmp56, err := this.SerialType.Code.Value()
		if err != nil {
			return err
		}
		switch (tmp56) {
		case 1:
			tmp57, err := this._io.ReadU1()
			if err != nil {
				return err
			}
			this.AsInt = tmp57
		case 2:
			tmp58, err := this._io.ReadU2be()
			if err != nil {
				return err
			}
			this.AsInt = tmp58
		case 3:
			tmp59, err := this._io.ReadBitsIntBe(24)
			if err != nil {
				return err
			}
			this.AsInt = tmp59
		case 4:
			tmp60, err := this._io.ReadU4be()
			if err != nil {
				return err
			}
			this.AsInt = tmp60
		case 5:
			tmp61, err := this._io.ReadBitsIntBe(48)
			if err != nil {
				return err
			}
			this.AsInt = tmp61
		case 6:
			tmp62, err := this._io.ReadU8be()
			if err != nil {
				return err
			}
			this.AsInt = tmp62
		}
	}
	tmp63, err := this.SerialType.Code.Value()
	if err != nil {
		return err
	}
	if (tmp63 == 7) {
		tmp64, err := this._io.ReadF8be()
		if err != nil {
			return err
		}
		this.AsFloat = float64(tmp64)
	}
	tmp65, err := this.SerialType.IsBlob()
	if err != nil {
		return err
	}
	if (tmp65) {
		tmp66, err := this.SerialType.LenContent()
		if err != nil {
			return err
		}
		tmp67, err := this._io.ReadBytes(int(tmp66))
		if err != nil {
			return err
		}
		tmp67 = tmp67
		this.AsBlob = tmp67
	}
	tmp68, err := this.SerialType.LenContent()
	if err != nil {
		return err
	}
	tmp69, err := this._io.ReadBytes(int(tmp68))
	if err != nil {
		return err
	}
	tmp69 = tmp69
	this.AsStr = string(tmp69)
	return err
}
type Sqlite3_RefCell struct {
	OfsBody uint16
	_io *kaitai.Stream
	_root *Sqlite3
	_parent *Sqlite3_BtreePage
	_f_body bool
	body kaitai.Struct
}
func NewSqlite3_RefCell() *Sqlite3_RefCell {
	return &Sqlite3_RefCell{
	}
}

func (this Sqlite3_RefCell) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp70, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.OfsBody = uint16(tmp70)
	return err
}
func (this *Sqlite3_RefCell) Body() (v kaitai.Struct, err error) {
	if (this._f_body) {
		return this.body, nil
	}
	this._f_body = true
	_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 10:
		tmp71 := NewSqlite3_CellIndexLeaf()
		err = tmp71.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.body = tmp71
	case 13:
		tmp72 := NewSqlite3_CellTableLeaf()
		err = tmp72.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.body = tmp72
	case 2:
		tmp73 := NewSqlite3_CellIndexInterior()
		err = tmp73.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.body = tmp73
	case 5:
		tmp74 := NewSqlite3_CellTableInterior()
		err = tmp74.Read(this._io, this, this._root)
		if err != nil {
			return nil, err
		}
		this.body = tmp74
	}
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.body, nil
}
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) IO_() *kaitai.Stream {
	return this._io
}

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

	tmp75 := NewVlqBase128Be()
	err = tmp75.Read(this._io, nil, nil)
	if err != nil {
		return err
	}
	this.Code = tmp75
	return err
}
func (this *Sqlite3_Serial) IsBlob() (v bool, err error) {
	if (this._f_isBlob) {
		return this.isBlob, nil
	}
	this._f_isBlob = true
	tmp76, err := this.Code.Value()
	if err != nil {
		return false, err
	}
	tmp78, err := this.Code.Value()
	if err != nil {
		return false, err
	}
	tmp77 := tmp78 % 2
	if tmp77 < 0 {
		tmp77 += 2
	}
	this.isBlob = bool( ((tmp76 >= 12) && (tmp77 == 0)) )
	return this.isBlob, nil
}
func (this *Sqlite3_Serial) IsString() (v bool, err error) {
	if (this._f_isString) {
		return this.isString, nil
	}
	this._f_isString = true
	tmp79, err := this.Code.Value()
	if err != nil {
		return false, err
	}
	tmp81, err := this.Code.Value()
	if err != nil {
		return false, err
	}
	tmp80 := tmp81 % 2
	if tmp80 < 0 {
		tmp80 += 2
	}
	this.isString = bool( ((tmp79 >= 13) && (tmp80 == 1)) )
	return this.isString, nil
}
func (this *Sqlite3_Serial) LenContent() (v int, err error) {
	if (this._f_lenContent) {
		return this.lenContent, nil
	}
	this._f_lenContent = true
	tmp82, err := this.Code.Value()
	if err != nil {
		return 0, err
	}
	if (tmp82 >= 12) {
		tmp83, err := this.Code.Value()
		if err != nil {
			return 0, err
		}
		this.lenContent = int((tmp83 - 12) / 2)
	}
	return this.lenContent, nil
}
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) IO_() *kaitai.Stream {
	return this._io
}

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 := 0;; i++ {
		tmp84, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp84 {
			break
		}
		tmp85 := NewSqlite3_Serial()
		err = tmp85.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Entries = append(this.Entries, tmp85)
	}
	return err
}