Sign in

    moonsqlitefile

    Pure MoonBit read-only SQLite file format parser and inspector

    sqlite
    parser
    database
    inspector
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    22 days ago
    Downloads
    1K

    No dependencies

    #MoonSQLiteFile

    CI

    纯 MoonBit 的 SQLite 3 数据库文件解析与检查库:直接解释磁盘格式,提供页面、记录和 schema API。适用于文件格式教学、离线数据库检查、跨后端的数据库结构浏览器。

    核心库只依赖 MoonBit 标准库,支持 Wasm、WasmGC、JS 与 native;Node CLI 宿主层只处理文件与进程 I/O。SQLite 引擎仅用于生成测试样本和对照结果。

    #已实现

    • 100 字节文件头验证、512–65536 字节页面、安全页访问。
    • 四类 B-tree 页头、cell pointer 与 freeblock 链检查。
    • 1–9 字节 varint、全部标准 serial types、64 位整数、浮点、NULL、BLOB。
    • UTF-8、UTF-16LE、UTF-16BE 严格解码。
    • 普通 rowid 表的多层 B-tree 遍历、父键范围与循环检查。
    • overflow 重组、sqlite_schema、表名解析与 freelist 检查。
    • JSON CLI、真实 SQLite 对照测试与 GitHub Actions CI。

    首版只读,不执行 SQL、不写数据库、不合并 WAL。索引与 WITHOUT ROWID 可检查页头,暂不遍历记录。输入应为安全获取的静态数据库副本;完整范围见 架构说明。

    #获取与运行

    要求 MoonBit release 工具链(本地验证 moon 0.1.20260920)、Node.js 22 或更新版本;对照验证还需要 Python 3.13。无 npm 依赖。

    git clone https://github.com/prowk/MoonSQLiteFile.git cd MoonSQLiteFile moon build --target js cmd/inspect node tools/inspect.cjs fixtures/core.sqlite header node tools/inspect.cjs fixtures/core.sqlite schema node tools/inspect.cjs fixtures/core.sqlite page 3 node tools/inspect.cjs fixtures/core.sqlite rows samples node tools/inspect.cjs fixtures/core.sqlite rows branches 5 node tools/inspect.cjs fixtures/core.sqlite freelist

    成功时 stdout 输出一行 JSON;失败时 stderr 输出错误,退出码非零。rows 默认最多 100000 行,传 0 返回空数组。整数和 rowid 用十进制字符串、BLOB 用十六进制,避免 JS 丢失 64 位精度。

    samples 第一行 rowid 为 "-7",中文字段为 "中文 SQLite 🌙";branches 共 680 行;freelist 共 7 页。样本可重复生成,见 fixtures 文档。

    #库 API

    Mooncakes 发布尚未执行。当前从源码构建;发布后模块名为 prowk/moonsqlitefile。消费包的 moon.pkg 导入:

    import {
    "prowk/moonsqlitefile" @sqlite,
    }

    宿主提供文件字节,库接收 Bytes:

    fn inspect(data : Bytes) -> Array[@sqlite.Row] raise @sqlite.SqliteError {
    let db = @sqlite.open_database(data)
    db.table_rows("samples", limit=10)
    }

    运行纯库示例:

    moon run --target js examples/basic

    输出 page_size=512, pages=1 与 schema entries=0。API 见 pkg.generated.mbti 和 架构说明。

    Row.values 是磁盘存储值,保持字段顺序:INTEGER PRIMARY KEY 通常为 Null,真实值位于 Row.rowid;REAL affinity 的值也可能存为 Integer。库不推断列名、主键别名或 SQL 默认值。

    #验证

    moon check --target all --deny-warn moon build --target all --deny-warn moon test --target all --deny-warn moon fmt --check python tools/generate_fixtures.py --check python tools/verify_oracle.py

    当前 31 项 MoonBit 测试在四个后端均通过。5 个固定样本与 3 个临时随机数据库共 1063 行,与 Python SQLite 查询结果逐字段比对;同时校验 schema、页数、freelist、Unicode、overflow 和 CLI 错误行为。Python 不参与核心运行时。

    #赛事与来源

    依据 SQLite 官方磁盘格式规范 独立实现,未移植第三方解析器。已有 SQLite binding 用于执行 SQL,本项目直接检查文件结构,差异及十月规则来源见 赛事工程记录。

    开发由 Codex AI 辅助,参赛者需理解并维护成果;正式一页申报书须人工撰写。目前工程准备不代表已报名或验收通过,后续还需 Mooncakes 发布、人工申报与报名材料提交。

    Apache-2.0 许可证,见 LICENSE 与 来源说明。

    SqliteError

    pub suberror SqliteError {
    Invalid(String)
    Unsupported(String)
    LimitExceeded(String)
    } derive(
    Debug
    )

    Database

    pub struct Database {
    data : Bytes
    header : Header
    page_count : Int
    limits : Limits
    }

    Database::freelist

    fn Database::freelist(self : Database) -> Array[Int] raise SqliteError

    返回 freelist 中的 trunk 与 leaf 页号,并校验计数与循环。

    Database::header

    fn Database::header(self : Database) -> Header

    Database::page

    fn Database::page(self : Database, number : Int) -> Page raise SqliteError

    Database::page_count

    fn Database::page_count(self : Database) -> Int

    Database::read_page

    fn Database::read_page(self : Database, number : Int) -> Bytes raise SqliteError

    Database::read_table

    fn Database::read_table(self : Database, root : Int, limit? : Int) -> Array[Row] raise SqliteError

    以 rowid 顺序读取普通表;limit 为零时不读取任何行。

    Database::schema

    fn Database::schema(self : Database) -> Array[SchemaEntry] raise SqliteError

    Database::table_rows

    fn Database::table_rows(self : Database, name : String, limit? : Int) -> Array[Row] raise SqliteError

    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
    text_encoding : Int
    user_version : UInt
    application_id : UInt
    version_valid_for : UInt
    sqlite_version : UInt
    } derive(Eq,
    Debug
    )

    Header::equal

    fn Header::equal(Header, Header) -> Bool

    Header::not_equal

    fn Header::not_equal(x : Header, y : Header) -> Bool

    Header::to_repr

    Limits

    pub(all) struct Limits {
    max_rows : Int
    max_payload_bytes : Int
    max_pages : Int
    max_depth : Int
    } derive(
    Debug
    )

    Limits::default

    fn Limits::default() -> Limits

    Limits::to_repr

    Page

    pub(all) struct Page {
    number : Int
    kind : PageType
    first_freeblock : Int
    cell_count : Int
    content_start : Int
    fragmented_bytes : Int
    right_child : Int?
    cell_offsets : Array[Int]
    } derive(
    Debug
    )

    Page::to_repr

    PageType

    pub(all) enum PageType {
    TableLeaf
    TableInterior
    IndexLeaf
    IndexInterior
    } derive(Eq,
    Debug
    )

    PageType::equal

    fn PageType::equal(PageType, PageType) -> Bool

    PageType::not_equal

    fn PageType::not_equal(x : PageType, y : PageType) -> Bool

    PageType::to_repr

    Row

    pub(all) struct Row {
    rowid : Int64
    values : Array[Value]
    page_number : Int
    } derive(
    Debug
    )

    Row::to_repr

    SchemaEntry

    pub(all) struct SchemaEntry {
    object_type : String
    name : String
    table_name : String
    root_page : Int
    sql : String?
    } derive(
    Debug
    )

    Value

    pub(all) enum Value {
    Null
    Integer(Int64)
    Real(Double)
    Text(String)
    Blob(Bytes)
    } derive(Eq,
    Debug
    )

    SQLite 记录中的原始值,保留整数、浮点数与二进制数据的区别。

    Value::equal

    fn Value::equal(Value, Value) -> Bool

    Value::not_equal

    fn Value::not_equal(x : Value, y : Value) -> Bool

    Value::to_repr

    decode_record

    fn decode_record(payload : Bytes, encoding : Int) -> Array[Value] raise SqliteError

    解码完整的 SQLite record payload;编码编号与数据库文件头保持一致。

    decode_varint

    fn decode_varint(data : Bytes, offset : Int) -> (UInt64, Int) raise SqliteError

    open_database

    fn open_database(data : Bytes, limits? : Limits) -> Database raise SqliteError

    parse_header

    fn parse_header(data : Bytes) -> Header raise SqliteError