Read-only SQLite database and WAL file analyzer written in MoonBit
Dependencies
git clone https://github.com/geniuszby/pagelens.git
cd pagelens
moon updatemoon add geniuszby/pagelens@0.1.0python3 scripts/generate_fixtures.py
moon run --target native cmd/pagelens -- inspect fixtures/generated/sample.dbpagelens inspect <database> [--json]
pagelens wal <wal-file> [--json]
pagelens snapshot <database> [--wal <wal-file>] [--json]
pagelens check <database> [--wal <wal-file>] [--json]moon run --target native cmd/pagelens --moon run --target native cmd/pagelens -- inspect app.db
moon run --target native cmd/pagelens -- inspect app.db --jsonmoon run --target native cmd/pagelens -- wal app.db-walmoon run --target native cmd/pagelens -- snapshot app.db
moon run --target native cmd/pagelens -- snapshot app.db --wal saved.wal --jsonmoon run --target native cmd/pagelens -- check app.db
moon run --target native cmd/pagelens -- check app.db --wal app.db-wal --jsonfile bytes
-> BinaryReader
-> database header / page layout
-> B-tree cells / records / overflow / freelist
-> WAL frames and commit boundaries
-> immutable SnapshotView
-> IntegrityReport
-> text or JSON CLI reportsmoon fmt --check
moon check --deny-warn
moon build
moon test --deny-warn
python3 scripts/generate_fixtures.py
moon run --target native cmd/pagelens -- check fixtures/generated/sample.dbmoon build --deny-warnmoon build --target native --deny-warnmoon package --list
moon publish --dry-runpub(all) struct BinaryReader {
data : Bytes
start : Int
limit : Int
position : Int
context : String
}fn BinaryReader::fork(self : BinaryReader, count : Int, context : String) -> BinaryReader raise ParseErrorfn BinaryReader::range(data : Bytes, offset : Int, length : Int, context : String) -> BinaryReader raise ParseErrorpub(all) struct BtreeTraversal {
root_page : UInt64
visits : Array[BtreeVisit]
diagnostics : Array[Diagnostic]
} derive(Eq, Debug)pub(all) struct DatabaseHeader {
page_size : Int
write_version : Int
read_version : Int
reserved_bytes : Int
max_embedded_payload_fraction : Int
min_embedded_payload_fraction : Int
leaf_payload_fraction : Int
file_change_counter : UInt64
database_size_pages : UInt64
first_freelist_trunk_page : UInt64
total_freelist_pages : UInt64
schema_cookie : UInt64
schema_format : UInt64
default_page_cache_size : Int64
largest_root_btree_page : UInt64
text_encoding : TextEncoding
user_version : UInt64
incremental_vacuum : UInt64
application_id : UInt64
version_valid_for : UInt64
sqlite_version_number : UInt64
} derive(Eq, Debug)fn DatabaseImage::page_reader(self : DatabaseImage, page_number : UInt64, context : String) -> BinaryReader raise ParseErrorfn DatabaseImage::validate_page_number(self : DatabaseImage, page_number : UInt64) -> Unit raise ParseErrorpub(all) struct DatabaseInspection {
header : DatabaseHeader
physical_page_count : UInt64
file_length : Int
page_one : BtreePageHeader
page_one_layout : PageLayout
schema_tree : BtreeTraversal
freelist : FreelistReport
diagnostics : Array[Diagnostic]
}fn Diagnostic::error(code : String, message : String, offset? : Int, page_number? : UInt64) -> Diagnosticfn Diagnostic::info(code : String, message : String, offset? : Int, page_number? : UInt64) -> Diagnosticfn Diagnostic::warning(code : String, message : String, offset? : Int, page_number? : UInt64) -> Diagnosticpub(all) struct FreelistReport {
trunks : Array[FreelistTrunk]
trunk_pages : Array[UInt64]
leaf_pages : Array[UInt64]
diagnostics : Array[Diagnostic]
declared_page_count : UInt64
} derive(Debug)pub(all) struct IntegrityReport {
diagnostics : Array[Diagnostic]
database_opened : Bool
pages_examined : Int
btree_pages : Int
btree_cells : Int
records_decoded : Int
overflow_pages : Int
freelist_pages : Int
wal_frames : Int
}pub(all) struct OverflowChain {
first_page : UInt64
pages : Array[UInt64]
payload : Bytes
diagnostics : Array[Diagnostic]
} derive(Eq, Debug)pub(all) struct PageDifference {
page_number : UInt64
frame_index : Int
changed_bytes : Int
first_changed_offset : Int?
last_changed_offset : Int?
ranges : Array[ChangedRange]
} derive(Eq, Debug)pub(all) struct RecordColumn {
index : Int
serial_type : UInt64
body_offset : Int
byte_length : Int
value : RecordValue
} derive(Eq, Debug)pub(all) struct SnapshotPage {
page_number : UInt64
source : SnapshotPageSource
bytes : Bytes
} derive(Eq, Debug)pub(all) struct SnapshotView {
database : DatabaseImage
wal : WalFile
max_frame : Int
logical_page_count : UInt64
}fn SnapshotView::at_commit(database : DatabaseImage, wal : WalFile, frame_index : Int) -> SnapshotView raise ParseErrorfn SnapshotView::difference_for_page(self : SnapshotView, page_number : UInt64) -> PageDifference? raise ParseErrorfn SnapshotView::read_page(self : SnapshotView, page_number : UInt64) -> SnapshotPage raise ParseErrorpub(all) struct SqliteRecord {
header_size : Int
body_offset : Int
columns : Array[RecordColumn]
trailing_bytes : Int
} derive(Eq, Debug)pub(all) struct WalFile {
header : WalHeader
frames : Array[WalFrame]
transactions : Array[WalTransaction]
diagnostics : Array[Diagnostic]
trailing_bytes : Int
last_commit_frame : Int?
} derive(Debug)pub(all) struct WalFrame {
index : Int
offset : Int
page_number : UInt64
database_size_after_commit : UInt64
salt_first : UInt64
salt_second : UInt64
checksum : WalChecksum
computed_checksum : WalChecksum
page_data : Bytes
salt_valid : Bool
checksum_valid : Bool
} derive(Eq, Debug)pub(all) struct WalHeader {
magic : UInt64
format_version : UInt64
page_size : Int
checkpoint_sequence : UInt64
salt_first : UInt64
salt_second : UInt64
checksum : WalChecksum
computed_checksum : WalChecksum
checksum_order : WalChecksumOrder
checksum_valid : Bool
} derive(Eq, Debug)fn analyze_page_layout(database : DatabaseImage, header : BtreePageHeader) -> PageLayout raise ParseErrorlet description : Stringfn local_payload_size(page_type : PageType, payload_size : Int, usable_size : Int) -> Int raise ParseErrorfn parse_btree_cell(database : DatabaseImage, header : BtreePageHeader, index : Int) -> BtreeCell raise ParseErrorfn parse_btree_page_cells(database : DatabaseImage, header : BtreePageHeader) -> Array[BtreeCell] raise ParseErrorfn parse_btree_page_header(database : DatabaseImage, page_number : UInt64) -> BtreePageHeader raise ParseErrorfn parse_freeblocks(database : DatabaseImage, header : BtreePageHeader) -> Array[Freeblock] raise ParseErrorfn parse_freelist_trunk(database : DatabaseImage, page_number : UInt64) -> FreelistTrunk raise ParseErrorfn read_overflow_chain(database : DatabaseImage, first_page : UInt64, payload_bytes : Int) -> OverflowChain raise ParseErrorfn traverse_btree(database : DatabaseImage, root_page : UInt64, max_depth? : Int) -> BtreeTraversal raise ParseErrorfn wal_checksum(bytes : Bytes, order : WalChecksumOrder, initial_first? : UInt64, initial_second? : UInt64) -> WalChecksum raise ParseErrorRead-only SQLite database and WAL file analyzer written in MoonBit
Dependencies