教程

创建本地数据库,
然后运行 SQL。

按下列步骤使用进程内 netbadb-sdk。默认特性为 embedded。只有需要 Protocol v2 客户端时才启用 remote。工具链 1.97.1;MSRV 1.85.0。

你将完成

  1. 在 Rust crate 中加入 netbadb-sdk
  2. 创建 Heap 文件、插入一行并用 SQL 查询
  3. 可选:检查 catalog,再启动 netbadbd 供远程客户端连接

引擎特点

  • 带名义语义类型的类型化 SQL 子集
  • 堆 MVCC、可选 LSM、WAL 与崩溃恢复
  • 每个打开的数据库一个写者;读已提交或可重复读

1. 添加依赖

该 crate 来自工作区仓库。Cargo 会在该 git workspace 中解析名为 netbadb-sdk 的包。

[dependencies]
netbadb-sdk = { git = "https://github.com/sskycn/netbadb" }
[dependencies]
netbadb-sdk = { git = "https://github.com/sskycn/netbadb", default-features = false, features = ["remote"] }

2. 创建、插入与查询

Database::create 拒绝覆盖已有数据库或 WAL 槽。insert 与 execute 作为隐式事务运行。create_index 回填当前行并注册非唯一单列索引。analyze 写入新的优化器快照;DML 不会自动刷新该快照。

use netbadb_sdk::{
    ColumnDef, ColumnId, Database, DatabaseError, PhysicalType, ScalarValue, TableDef, TableId,
    TypeSpec,
};

fn users() -> TableDef {
    TableDef::new(
        TableId(1),
        "users",
        vec![
            ColumnDef::new(
                ColumnId(1),
                "id",
                TypeSpec::Semantic {
                    name: "UserId".into(),
                    physical: PhysicalType::UInt64,
                },
            ),
            ColumnDef::new(ColumnId(2), "name", TypeSpec::Physical(PhysicalType::Text)),
        ],
    )
}

fn main() -> Result<(), DatabaseError> {
    let mut database = Database::create("users.db", users())?;
    database.insert(&[
        ScalarValue::UInt64(1),
        ScalarValue::Text("Ada".into()),
    ])?;
    database.create_index(TableId(1), ColumnId(1))?;
    database.analyze(TableId(1))?;
    let _rows = database.query("SELECT id, name FROM users WHERE id = 1")?;
    database.close()
}

3. 检查目录与计划

检查会编译并规划语句,但不会执行。它不会扫描堆、刷新 ANALYZE、获取写者或追加 WAL。

use netbadb_sdk::inspection;

let catalog = database.inspect_catalog()?;
println!("{}", inspection::render_catalog(&catalog));

let statement = database.inspect_statement(
    "SELECT id FROM users WHERE id = 1",
)?;
println!("{}", inspection::render_statement(&statement));

4. 启动 netbadbd

服务器打开部署清单 v11 声明的已有堆文件。版本 1 至 10 均被拒绝。回环明文要求恰好一个 local_plaintext 主体。非回环监听要求双向 TLS。

{
  "version": 11,
  "listen": "127.0.0.1:7878",
  "authorization": {
    "local_plaintext": {
      "tables": [
        { "table_id": 1, "read": true, "write": true, "transaction": true, "analyze": true }
      ]
    },
    "clients": []
  },
  "tables": [
    {
      "path": "users.db",
      "id": 1,
      "name": "users",
      "columns": [
        { "id": 1, "name": "id", "physical_type": "uint64", "semantic_type": "UserId", "nullable": false },
        { "id": 2, "name": "name", "physical_type": "text", "nullable": false }
      ]
    }
  ]
}
cargo run -p netbadbd -- --manifest server.json

5. 连接远程客户端

仅当解析后的 TCP 对端为回环地址时才接受明文。远程部署要求经过校验的双向 TLS。不提供连接池、自动重试或多路复用。

use netbadb_sdk::remote;

let mut client = remote::Client::connect(
    remote::Config::new("127.0.0.1:7878"),
)?;
client.ping()?;
let mut rows = client.query("SELECT id, name FROM users ORDER BY id")?;
while let Some(values) = rows.next_row()? {
    println!("{values:?}");
}

隔离级别

begin_transaction 使用读已提交。可重复读通过 begin_transaction_with_isolation 提供。IsolationLevel 由 netbadb-core 导出。不提供可串行化隔离。

use netbadb_core::IsolationLevel;

let mut tx = database.begin_transaction_with_isolation(
    IsolationLevel::RepeatableRead,
)?;

SQL DDL

Heap CREATE TABLE 接受物理类型 v2 名称,包括 BOOLEAN、整数宽度、TEXT/VARCHAR、REAL/DOUBLE、BYTEA 以及原生 UINT*。DROP TABLE 在 prepare 时绑定身份。ALTER TABLE 支持改表名 / 列名、可空 ADD、受限 DROP 与 SET/DROP NOT NULL。CREATE INDEX / DROP INDEX 管理单列非唯一 Heap BTree。网络 DDL 需要 schema_admin。不提供 PostgreSQL 协议兼容。

CREATE TABLE projects (
    id BIGINT NOT NULL,
    name TEXT,
    active BOOLEAN NOT NULL
);
ALTER TABLE projects ADD COLUMN notes TEXT;
ALTER TABLE projects ALTER COLUMN name SET NOT NULL;
CREATE INDEX projects_id_idx ON projects (id);
DROP INDEX projects_id_idx;
ALTER TABLE projects DROP COLUMN notes;
DROP TABLE projects;

LSM、分区、catalog 与 vacuum

Database::create_storages 可创建 Heap 或 LSM 表。create_with_placements 挂载 RANGE 分区。open_catalog 无需外部 TableDef 即可打开已发布的 schema catalog。vacuum 回收活动快照不可见的死亡堆版本。列存投影是派生、可选的,已提交 DML 之后在刷新前会过期。

use netbadb_sdk::{ColumnId, Database, TableStorageCreateSpec};

let mut database = Database::create_storages(vec![
    TableStorageCreateSpec::lsm("users-lsm", users(), ColumnId(1)),
])?;
database.vacuum(TableId(1))?;
let mut reopened = Database::open_catalog("catalog")?;

本地运维平面

NBOP v7 是由清单 v11 配置的 Unix 域运维协议,不是数据库线协议。Native Protocol v2 仍是唯一的网络数据库前端。

{
  "operator": {
    "unix_socket": "run/netbadb-operator.sock",
    "io_timeout_ms": 5000,
    "allow_physical_index_apply": false,
    "allow_physical_columnar_apply": false,
    "allow_physical_design_receipt_read": false,
    "physical_index_admission": {"mode": "unadmitted"},
    "physical_columnar_snapshot_admission": {"mode": "unadmitted"},
    "physical_columnar_incremental_admission": {"mode": "unadmitted"}
  }
}

6. 使用命令行检查文件

请先停止 netbadbd 以及任何使用同一文件的嵌入式进程。CLI 通过正常启动恢复打开表,并且不会执行被检查的 SQL。JSON 输出使用 Inspection JSON v7。

cargo run -p netbadb -- inspect catalog --manifest server.json

cargo run -p netbadb -- inspect statement \
  --manifest server.json \
  --sql "SELECT id FROM users WHERE id = 1" \
  --format json

Go 客户端

Go 模块是独立的 Protocol v2 客户端,不使用 cgo 或 Rust FFI。Dial 会自动完成 Hello。Go 客户端拒绝 Int128 与 UInt128 结果类型。

client, err := netbadb.Dial(ctx, netbadb.Config{
    Address: "localhost:7878",
})
if err != nil { /* handle */ }
defer client.Close()

rows, err := client.Query(ctx, "SELECT id, name FROM users ORDER BY id")

编辑器诊断

netbadb-lsp --schema schema.json 是仅提供诊断的 stdio 语言服务器。它会一次性加载 SDK Schema Spec v1 或 v2。它不会打开数据库文件,也不报告物理计划。

netbadb-lsp --schema schema.json

从源码构建

git clone https://github.com/sskycn/netbadb.git
cd netbadb
make test

运行约束

  • 每个打开的数据库对象允许一个写者。只读事务不预定写者。
  • 显式事务支持读已提交与可重复读。隐式语句使用读已提交。不提供可串行化隔离。
  • 成功的提交表示 Commit 记录已持久化;堆页可能仍留在缓冲中,直到 flush、vacuum 或 close。
  • Heap 表支持 SQL CREATE TABLE、DROP TABLE、ALTER TABLE、CREATE INDEX 与 DROP INDEX。不支持 PRIMARY KEY、IF EXISTS 与通用 ALTER COLUMN TYPE。
  • 多存储写入经协调日志提交。不提供并发写者与跨进程文件锁。
  • 实验性磁盘格式会拒绝旧版本,不提供迁移路径。

许可

NetbaDB 以 AGPL-3.0-or-later 授权。如果修改程序并让用户通过网络与之交互,必须提供对应源代码。

常见问题

如何在 Rust 进程内嵌入 NetbaDB?

从 GitHub workspace 添加 netbadb-sdk,调用 Database::create,然后在进程内插入与查询。默认特性为 embedded。

netbadbd 使用什么协议?

仅 Native Protocol v2。当前启动契约是清单 v11。PostgreSQL 协议与 netbadbd --postgres 已被移除。

有哪些隔离级别?

显式事务支持读已提交与可重复读。隐式语句使用读已提交。不提供可串行化隔离。