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".
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.
// 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
}