> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 使用 Rust 构建扩展

> 开始使用 VillageSQL Rust SDK — 使用安全的 Rust 编写扩展函数，将其打包为 VEB 文件，并将其安装到 VillageSQL 中。

> [!NOTE]
>
> 如果您更喜欢 C++，请参阅 [使用 C++ 创建扩展](https://villagesql.com/docs/zh/extensions/build/create.md)，了解 C++ SDK 的操作指南。

可以使用 `villagesql` crate 用 Rust 编写 VillageSQL 扩展。SDK 处理所有 FFI 编组 — 您可以使用普通的 Rust 类型，`extension!` 宏会生成服务器在加载时调用的 C 入口点。

## 先决条件

在开始之前，请先从源代码构建 VillageSQL — `cargo vsql install` 和 `cargo vsql test` 会使用服务器的构建树。请先按照 [从源代码构建](https://villagesql.com/docs/zh/8.4/stable/source.md) 指南操作。

您还需要：

* **Rust 稳定工具链** — 在 [rustup.rs](https://rustup.rs) 上安装
* **Git** — 用于克隆 SDK 和您的扩展仓库
* **cargo-vsql** — Cargo 的子命令，用于打包、安装和测试扩展
* **VillageSQL 构建目录** — 将 `VillageSQL_BUILD_DIR` 设置为服务器的构建路径，以便 `cargo vsql install` 和 `cargo vsql test` 正常工作
* **基本的 Rust 知识** — 熟悉 Cargo、枚举和模式匹配

从 SDK 仓库安装 `cargo-vsql`：

```bash theme={null}
git clone https://github.com/villagesql/vsql-rust-sdk
cd vsql-rust-sdk
cargo install --path cargo-vsql
```

验证它是否可用：

```bash theme={null}
cargo vsql --help
```

## 创建一个新的 crate

创建一个新的 Rust 库 crate 并添加 SDK：

```bash theme={null}
cargo new --lib vsql_rot13
cd vsql_rot13
cargo add villagesql
```

然后在 `Cargo.toml` 中设置 crate 类型：

```toml theme={null}
[lib]
crate-type = ["cdylib"]
```

`cdylib` crate 类型告诉 Cargo 生成一个共享库（Linux 上的 `.so`，macOS 上的 `.dylib`），服务器可以加载它。

## 编写您的第一个函数

将 `src/lib.rs` 替换为完整的扩展：

```rust theme={null}
use villagesql::{InValue, VdfReturn};

fn rot13_impl(args: &[InValue]) -> VdfReturn {
    match args.first() {
        Some(InValue::String(s)) => VdfReturn::string(rot13(s)),
        Some(InValue::Null) | None => VdfReturn::null(),
        _ => VdfReturn::error("vsql_rot13: expected a STRING argument"),
    }
}

fn rot13(s: &str) -> String {
    s.chars()
        .map(|c| match c {
            'a'..='m' | 'A'..='M' => (c as u8 + 13) as char,
            'n'..='z' | 'N'..='Z' => (c as u8 - 13) as char,
            _ => c,
        })
        .collect()
}

villagesql::extension! {
    funcs: [
        villagesql::func!(rot13_impl, "vsql_rot13", [villagesql::Type::String] -> villagesql::Type::String),
    ]
}
```

`func!` 宏将 `rot13_impl` 绑定到 SQL 名称 `vsql_rot13`，签名是 `STRING -> STRING`。

函数签名是 `fn(&[InValue]) -> VdfReturn`。`InValue` 是服务器传递的 SQL 类型枚举。`VdfReturn` 是您返回的内容。在访问值之前，检查 `args.first()` 以处理 NULL 情况和类型错误的情况。

如果您的函数对于相同的输入始终返回相同的输出，请声明为确定性函数 — 只有确定性函数才能出现在生成列或 `CHECK` 约束中：

```rust theme={null}
villagesql::func!(rot13_impl, "vsql_rot13", [villagesql::Type::String] -> villagesql::Type::String, deterministic: true)
```

## 添加 manifest.json

在 crate 根目录（`Cargo.toml` 旁边）创建 `manifest.json`：

```json theme={null}
{
  "name": "vsql_rot13",
  "version": "0.1.0",
  "description": "ROT-13 encoding for VillageSQL",
  "author": "Your Name",
  "license": "GPL-2.0"
}
```

服务器会在安装时读取此文件。`name` 字段必须与 `Cargo.toml` 中 `[package]` 部分的 `name` 以及您传递给 `INSTALL EXTENSION` 的内容匹配。

## 构建和安装

> [!NOTE]
>
> 从扩展目录（`Cargo.toml` 和 `manifest.json` 所在的位置）运行 `cargo vsql package`、`cargo vsql install` 和 `cargo vsql test`，而不是从工作区根目录运行。

将扩展打包到 `.veb` 文件中：

```bash theme={null}
cargo vsql package
```

这将生成 `dist/vsql_rot13.veb`。要将 VEB 打包并直接复制到您的 VillageSQL 构建目录：

```bash theme={null}
export VillageSQL_BUILD_DIR=/path/to/villagesql/build
cargo vsql install
```

要在开发期间使用本地副本覆盖依赖项，请传递 `--config KEY=VALUE`（可重复）：

```bash theme={null}
cargo vsql install --config 'patch.crates-io.villagesql.path="/path/to/villagesql"'
```

您应该看到 VEB 复制到扩展目录。验证其是否已正确放置：

```bash theme={null}
ls "$VillageSQL_BUILD_DIR/veb_output_directory/"
# vsql_rot13.veb
```

> [!NOTE]
>
> **0.0.8-dev 中的变更。** `cargo vsql install` 会将 VEB 复制到 `$VillageSQL_BUILD_DIR/lib/veb/`。

## 测试

在 `mysql-test/t/rot13_basic.test` 中编写一个测试文件：

```sql theme={null}
INSTALL EXTENSION vsql_rot13;
SELECT vsql_rot13('Hello');
SELECT vsql_rot13('');
SELECT vsql_rot13(NULL);
UNINSTALL EXTENSION vsql_rot13;
```

生成预期的结果：

```bash theme={null}
cargo vsql test --record
```

运行测试套件：

```bash theme={null}
cargo vsql test
```

在修改函数的行为后，重新运行 `cargo vsql test --record` 以更新预期的结果，然后运行 `cargo vsql test` 以确认。

## 在 SQL 中安装

VEB 位于扩展目录中后，安装它：

```sql theme={null}
INSTALL EXTENSION vsql_rot13;
```

验证：

```sql theme={null}
SELECT * FROM INFORMATION_SCHEMA.EXTENSIONS WHERE EXTENSION_NAME = 'vsql_rot13';
```

调用它：

```sql theme={null}
SELECT vsql_rot13('Hello, World!');
-- → Uryyb, Jbeyq!
```

## 后续步骤

本演练构建的是一个标量函数。[vsql-rust-sdk](https://github.com/villagesql/vsql-rust-sdk) 仓库中的两个完整示例则分别涵盖聚合和变长参数支持：

* [`examples/vsql_agg_sum`](https://github.com/villagesql/vsql-rust-sdk/tree/main/examples/vsql_agg_sum)——一个用 `agg_func!` 重新实现 `SUM` 的聚合 VDF，在每组累加器上使用独立的 `clear`、`accumulate` 和 `result` 回调。
* [`examples/vsql_varargs`](https://github.com/villagesql/vsql-rust-sdk/tree/main/examples/vsql_varargs)——用 `varargs_func!` 构建的四个变长参数函数：`str_join`（带验证、有状态）、`arg_count`（无验证、无状态）、`describe`（带验证、无状态、混合 INT/REAL/STRING 参数）和 `point_path`（针对自定义 `point2d` 类型的变长参数）。

每个示例都附带完整的 `Cargo.toml`、`manifest.json` 和 MTR 测试。

> [card] [Rust 中的自定义类型](https://villagesql.com/docs/zh/sdk/rust/custom-types.md)
>
> 定义具有二进制存储、排序和哈希的新列类型。

> [card] [Rust API 参考](https://villagesql.com/docs/zh/sdk/rust/api-reference.md)
>
> InValue、VdfReturn、extension!、func! 和 custom\_type! — 所有字段。

> [card] [Rust 中的预览功能](https://villagesql.com/docs/zh/sdk/rust/preview-capabilities.md)
>
> 通过 requires: 列表使用状态变量、系统变量、后台线程工作者和
> 密钥环访问。

> [card] [C++ SDK（创建扩展）](https://villagesql.com/docs/zh/extensions/build/create.md)
>
> C++ 方案 — 类型化包装器、构建器 API 和 CMake 设置。

> [card] [扩展架构](https://villagesql.com/docs/zh/extensions/build/architecture.md)
>
> VEB 文件如何加载、生命周期钩子和符号隔离。

> [card] [测试依赖网络的扩展](https://villagesql.com/docs/zh/sdk/cpp/testing-network.md)
>
> 针对会启动 HTTP 服务器或外部监听器的扩展的 MTR 端口模式 — 同样适用于 Rust 和 C++ 扩展。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.