Pure MoonBit read-only SQLite file format parser and inspector
moon add prowk/moonsqlitefile@0.7.0import {
"prowk/moonsqlitefile" @sqlite,
}fn read_rows(data : Bytes) -> Array[@sqlite.Row] raise @sqlite.SqliteError {
let db = @sqlite.open_database(data)
db.table_rows("samples", limit=10)
}fn read_records(data : Bytes) -> Array[@sqlite.BTreeRecord] raise @sqlite.SqliteError {
let db = @sqlite.open_database(data)
db.table_records("keyed", limit=10)
}
fn read_index(data : Bytes) -> Array[@sqlite.BTreeRecord] raise @sqlite.SqliteError {
let db = @sqlite.open_database(data)
db.index_records("mixed_index", limit=10)
}fn scan_records(
data : Bytes,
root_page : Int,
consume : (@sqlite.BTreeRecord) -> Bool raise @sqlite.SqliteError,
) -> @sqlite.ScanSummary raise @sqlite.SqliteError {
let db = @sqlite.open_database(data)
db.scan_btree(root_page, consume, limit=1000, max_total_payload_bytes=8388608UL)
}fn inspect_file(data : Bytes) -> @sqlite.DatabaseInspection raise @sqlite.SqliteError {
let db = @sqlite.open_database(data)
db.inspect_database(max_total_payload_bytes=67108864UL, max_issues=100)
}fn read_committed(db_bytes : Bytes, wal_bytes : Bytes) -> @sqlite.Database raise @sqlite.SqliteError {
@sqlite.open_wal_database(db_bytes, wal_bytes)
}git clone https://github.com/prowk/MoonSQLiteFile.git
cd MoonSQLiteFile
moon build --target js cmd/inspect
node tools/inspect.cjs fixtures/core.sqlite schema
node tools/inspect.cjs fixtures/core.sqlite rows samples 10
node tools/inspect.cjs fixtures/btree.sqlite index mixed_index 5
node tools/inspect.cjs fixtures/btree.sqlite inspect
node tools/inspect.cjs fixtures/btree.sqlite summary| 命令 | 用途 |
|---|---|
| header | 读取数据库文件头 |
| schema | 列出 schema 条目及根页号 |
| page <number> | 检查指定 B-tree 页 |
| page-inspect <number> | 返回 B-tree 页空间统计与错误位置 |
| rows <table> [limit] | 读取普通 rowid 表 |
| records <table> [limit] | 读取普通表或 WITHOUT ROWID 表的原始记录 |
| index <name> [limit] | 读取索引原始记录 |
| scan <root> [limit] | 扫描指定根页,输出记录和扫描状态 |
| freelist | 检查空闲页链 |
| inspect | 输出全局页归属、Ptrmap 校验及结构化诊断 |
| tree-inspect <root> [limit] | 输出单树检查进度和失败位置 |
| inspect-details | 输出全局报告及各条诊断的位置 |
| summary | 中文检查摘要、页面分类、对象占页及诊断 |
| summary-json | 精简 JSON 汇总,适合展示层消费 |
| viewer-data | 同一次扫描的文件头、汇总、详细诊断与导航数据 |
| wal-inspect | 输入为 WAL 文件,输出连续有效帧和提交边界 |
| wal-info | 配合 --wal 输出帧报告、最新快照页数与尾部策略 |
node tools/inspect.cjs snapshot.wal wal-inspect
node tools/inspect.cjs snapshot.db --wal snapshot.wal wal-info
node tools/inspect.cjs snapshot.db --wal snapshot.wal inspect-detailsmoon run --target js examples/basicpage_size=512, pages=1
schema entries=0moon check --target all --deny-warn
moon build --target all --deny-warn
moon test --target all --deny-warn
moon fmt --check
python tools/verify_api.py
python tools/generate_fixtures.py --check
python tools/verify_oracle.py
python tools/generate_btree_fixtures.py --check
python tools/verify_btree_oracle.py
python tools/verify_inspection.py
python tools/verify_wal_oracle.py
python tools/verify_review.py
node tools/verify_range_io.cjs
node tools/verify_wide_wal.cjs
python tools/verify_large_payload.py
python tools/benchmark_io.py
moon run --target js examples/basic
python tools/verify_consumer.py
python tools/build_viewer.py
node tools/verify_viewer.cjs
python tools/build_async.py
node tools/verify_async.mjs
python tools/verify_async_package.py
python tools/verify_async_wal.py
python tools/generate_browser_fixtures.py
node tools/verify_browser.cjs
node tools/fuzz.cjs --seed 20261003 --iterations 512pub(open) trait PageSource {
fn byte_length(Self) -> Int
fn read_range(Self, Int, Int) -> Bytes raise SqliteError
}pub(open) trait RangeSource {
fn byte_length64(Self) -> Int64
fn read_range64(Self, Int64, Int) -> Bytes raise SourceError
}pub(all) suberror SourceError {
HostFailure(String)
ShortRead(String)
RangeOutOfBounds(String)
}pub(all) suberror SqliteError {
Invalid(String)
Unsupported(String)
LimitExceeded(String)
} derive(Debug)pub struct BTreeCursor {
// private fields
}fn BTreeCursor::provide_page(self : BTreeCursor, number : Int, bytes : Bytes) -> Unit raise SqliteErrorpub(all) struct BTreeInspection {
root_page : Int
status : InspectionStatus
records_decoded : Int
summary : ScanSummary?
error : SqliteError?
} derive(Debug)pub(all) struct BTreeInspectionDetails {
inspection : BTreeInspection
location : DiagnosticLocation?
} derive(Debug)pub struct BytesSource {
data : Bytes
}impl PageSource for BytesSourceimpl RangeSource for BytesSourcefn BytesSource::read_range(self : BytesSource, offset : Int, count : Int) -> Bytes raise SqliteErrorfn BytesSource::read_range64(self : BytesSource, offset : Int64, count : Int) -> Bytes raise SourceErrorpub(all) struct CacheStatistics {
hits : Int64
misses : Int64
bytes_read : Int64
resident_pages : Int
} derive(Debug)pub struct CachedSource {
// private fields
}impl RangeSource for CachedSourcefn CachedSource::new(source : &RangeSource, block_size? : Int, max_pages? : Int) -> CachedSource raise SqliteErrorfn CachedSource::read_range64(self : CachedSource, offset : Int64, count : Int) -> Bytes raise SourceErrorpub struct Database {
source : &PageSource
header : Header
page_count : Int
limits : Limits
// private fields
}fn Database::index_records(self : Database, name : String, limit? : Int) -> Array[BTreeRecord] raise SqliteErrorfn Database::inspect_btree(self : Database, root : Int, limit? : Int, max_total_payload_bytes? : UInt64) -> BTreeInspectionfn Database::inspect_btree_details(self : Database, root : Int, limit? : Int, max_total_payload_bytes? : UInt64) -> BTreeInspectionDetailsfn Database::inspect_database(self : Database, max_total_payload_bytes? : UInt64, max_issues? : Int) -> DatabaseInspectionfn Database::inspect_database_details(self : Database, max_total_payload_bytes? : UInt64, max_issues? : Int) -> DatabaseInspectionDetailsfn Database::inspection_cursor(self : Database, max_total_payload_bytes? : UInt64, max_issues? : Int) -> InspectionCursorfn Database::read_btree(self : Database, root : Int, limit? : Int, max_total_payload_bytes? : UInt64) -> Array[BTreeRecord] raise SqliteErrorfn Database::read_index(self : Database, root : Int, limit? : Int) -> Array[BTreeRecord] raise SqliteErrorfn Database::scan_btree(self : Database, root : Int, visit : (BTreeRecord) -> Bool raise SqliteError, limit? : Int, max_total_payload_bytes? : UInt64) -> ScanSummary raise SqliteErrorfn Database::scan_cursor(self : Database, root : Int, limit? : Int, max_total_payload_bytes? : UInt64, table_only? : Bool) -> BTreeCursor raise SqliteErrorfn Database::table_records(self : Database, name : String, limit? : Int) -> Array[BTreeRecord] raise SqliteErrorpub(all) struct DatabaseInspection {
status : InspectionStatus
ownership_complete : Bool
ptrmap_checked : Bool
diagnostics_truncated : Bool
roots_inspected : Int
records_decoded : Int
payload_bytes : UInt64
pages : Array[PageOwnership]
unclaimed_pages : Array[Int]
issues : Array[DatabaseIssue]
} derive(Debug)pub(all) struct DatabaseInspectionDetails {
inspection : DatabaseInspection
issues : Array[LocatedDatabaseIssue]
} derive(Debug)pub(all) enum DatabaseIssue {
ScanError(Int?, SqliteError)
PageConflict(PageOwnership, PageOwnership)
UnclaimedPage(Int)
UnsupportedFeature(String)
PtrmapMismatch(PtrmapEntry, PageOwnership)
} derive(Debug)pub(all) struct DiagnosticLocation {
phase : DiagnosticPhase
page_number : Int?
byte_offset : Int?
cell_index : Int?
page_diagnostic : PageDiagnostic?
} derive(Debug)pub(all) struct Header {
page_size : Int
usable_size : Int
write_version : Int
read_version : Int
change_counter : UInt
declared_pages : UInt
freelist_trunk : UInt
freelist_pages : UInt
schema_cookie : UInt
schema_format : Int
largest_root_page : UInt
incremental_vacuum : Bool
text_encoding : Int
user_version : UInt
application_id : UInt
version_valid_for : UInt
sqlite_version : UInt
} derive(Eq, Debug)pub struct InspectionCursor {
// private fields
}fn InspectionCursor::provide_page(self : InspectionCursor, number : Int, bytes : Bytes) -> Unit raise SqliteErrorfn InspectionCursor::reject_page(self : InspectionCursor, reason : SqliteError) -> Unit raise SqliteErrorfn InspectionCursor::stop(self : InspectionCursor, reason? : SqliteError) -> DatabaseInspectionDetailspub(all) enum InspectionEvent {
NeedInspectionPage(Int)
InspectionProgress(ScanProgress)
InspectionFinished(DatabaseInspectionDetails)
} derive(Debug)pub(all) struct InspectionSummary {
claimed_pages : Int
unclaimed_pages : Int
page_kinds : Array[PageKindCount]
objects : Array[ObjectPageCount]
} derive(Eq, Debug)pub(all) struct Limits {
max_rows : Int
max_payload_bytes : Int
max_pages : Int
max_depth : Int
} derive(Debug)pub(all) struct LocatedDatabaseIssue {
issue : DatabaseIssue
location : DiagnosticLocation?
} derive(Debug)pub(all) struct PageDiagnostic {
code : PageDiagnosticCode
page_number : Int
byte_offset : Int?
cell_index : Int?
error : SqliteError
} derive(Debug)pub(all) struct PageInspection {
status : InspectionStatus
page : Page?
statistics : PageStatistics?
diagnostic : PageDiagnostic?
} derive(Debug)impl RangeSource for PageSourceAdapterfn PageSourceAdapter::read_range64(self : PageSourceAdapter, offset : Int64, count : Int) -> Bytes raise SourceErrorpub(all) struct PageStatistics {
database_header_bytes : Int
btree_header_bytes : Int
pointer_bytes : Int
unallocated_bytes : Int
cell_bytes : Int
freeblock_bytes : Int
fragmented_bytes : Int
reserved_bytes : Int
payload_bytes : UInt64
local_payload_bytes : UInt64
max_payload_bytes : Int
overflow_cells : Int
} derive(Debug)pub(all) struct PtrmapEntry {
page_number : Int
map_page : Int
kind : PtrmapType
parent_page : Int
} derive(Eq, Debug)pub(all) struct RangeWalInspection {
header : WalHeader?
frames : Array[RangeWalFrame]
commits : Array[RangeWalCommit]
committed_frames : Int
database_pages : UInt?
stop_reason : WalStopReason
stop_offset : Int64
trailing_bytes : Int64
} derive(Debug)pub struct RangeWalSource {
// private fields
}impl RangeSource for RangeWalSourcefn RangeWalSource::from_cursor(base : &RangeSource, wal : &RangeSource, cursor : WalCursor, tail_policy? : WalTailPolicy, max_overlay_pages? : Int) -> RangeWalSource raise SqliteErrorfn RangeWalSource::new(base : &RangeSource, wal : &RangeSource, tail_policy? : WalTailPolicy, max_frames? : Int, max_overlay_pages? : Int) -> RangeWalSource raise SqliteErrorfn RangeWalSource::page_range(self : RangeWalSource, number : Int) -> SnapshotPageRange raise SqliteErrorfn RangeWalSource::read_range64(self : RangeWalSource, offset : Int64, count : Int) -> Bytes raise SourceErrorpub(all) enum ScanEvent {
NeedPage(Int)
RecordReady(BTreeRecord)
ScanFinished(ScanSummary)
} derive(Debug)pub(all) struct ScanSummary {
records_read : Int
pages_read : Int
payload_bytes : UInt64
completion : ScanCompletion
} derive(Debug)pub(all) struct SchemaEntry {
object_type : String
name : String
table_name : String
root_page : Int
sql : String?
} derive(Debug)pub struct WalCursor {
// private fields
}pub(all) struct WalHeader {
checksum_order : WalChecksumOrder
version : UInt
page_size : Int
checkpoint_sequence : UInt
salt1 : UInt
salt2 : UInt
checksum1 : UInt
checksum2 : UInt
} derive(Eq, Debug)pub struct WalSource {
base : &PageSource
wal : Bytes
page_size : Int
page_count : Int
base_pages : Int
overlay : Map[Int, Int]
inspection : WalInspection
}impl PageSource for WalSourcefn WalSource::new(base : &PageSource, wal : Bytes, tail_policy? : WalTailPolicy, max_frames? : Int) -> WalSource raise SqliteErrorfn inspect_wal_source(source : &RangeSource, max_frames? : Int) -> RangeWalInspection raise SqliteErrorfn open_range_source(source : &RangeSource, limits? : Limits, max_report_pages? : Int) -> Database raise SqliteErrorfn open_range_wal_source(source : RangeWalSource, limits? : Limits, max_report_pages? : Int) -> Database raise SqliteErrorfn open_wal_database(base : Bytes, wal : Bytes, limits? : Limits, tail_policy? : WalTailPolicy, max_frames? : Int) -> Database raise SqliteErrorInstall
Download zipPure MoonBit read-only SQLite file format parser and inspector