examples/ ディレクトリには、サポートされているRustにおけるプレビュー機能ごとの例も 1 つずつ含まれています。
ソース: vsql-rust-sdk の examples/
vsql_rot13 — 関数のみの拡張
考えられる最も単純な Rust 拡張です。STRING を受け取り STRING を返す 1 つの VDF です。 使用例:ディレクトリ構造
実装
ファイル:src/lib.rs
- VDF は
&[InValue]を受け取りVdfReturnを返します。どちらも安全な Rust の列挙型です - NULL は両側で第一級のバリアントです。直接パターンマッチできます
extension!マクロは、サーバーがロード時に呼び出す C エントリポイントを生成しますfunc!は SQL シグネチャを宣言します。引数と戻り値の型にはvillagesql::Type::*を使用します
マニフェスト
ファイル:manifest.json
vsql_rational — 算術演算を備えたカスタム型
完全なカスタム型です。有理数を約分された形の(numerator, denominator) として格納し、算術関数、順序付け、ハッシュ化を備えています。
使用例:
バイナリ格納形式
rational は 16 バイト (リトルエンディアン) を格納します。
- バイト 0–7: 分子 (
i64) - バイト 8–15: 分母 (
i64)
型システム関数
ファイル:src/lib.rs
この型は 4 つの操作を登録します。エンコード (文字列 → バイト)、デコード (バイト → 文字列)、比較 (ORDER BY 用)、ハッシュ (インデックス作成用) です。
VDF の実装
カスタム型を受け取る VDF はInValue::Custom(&[u8]) を受け取り、バイトを自身でデコードします。
登録
extension! マクロは、型とその関数の両方を 1 つの宣言で登録します。
villagesql::custom!("name")は、引数または戻り値としてカスタム型を参照しますcustom_type!は、型をその encode/decode/compare/hash 関数とともに登録しますdefault: "0/1"は組み込みのデフォルト値です。サーバーは型の初期化時にこの文字列に対してencode()を呼び出すため、有効な値である必要がありますpersisted_lengthはencode()が返すバイト長と一致する必要がありますdeterministic: trueにより、オプティマイザは定数呼び出しを畳み込むことができます
vsql_agg_sum — 集約関数
INT 列に対する SUM を再実装した集約 VDF です。集約に必要な 3 つのフック — clear、accumulate、および結果関数 — と、それぞれが同じアキュムレーターをどのように参照するかを示します。
使用例:
アキュムレーターのライフサイクル
アキュムレーターはステートメントごとに 1 つの値であり、すべてのグループで再利用されます。サーバーは決まった順序でこれを駆動します。clear は各グループの開始時にアキュムレーターをリセットします。リセットし忘れたフィールドは前のグループから漏れます。
サーバーは、引数が NULL の行を含むすべての行に対して accumulate を呼び出します。NULL のスキップは関数の仕事です。必要なバリアントのみをマッチさせ、それ以外は無視してください。
実装
ファイル:src/lib.rs
seen フラグは、合計が 0 になったグループと、合計するものが何もなかったグループを区別します。これがないと、空のグループやすべて NULL のグループは、組み込みの SUM が NULL を返すところで 0 を返してしまいます。
登録
- 最初の識別子は結果関数であり、行関数ではありません。集約の行ごとの処理は
accumulate:にあります state:はアキュムレーターの型を指定します。この型はDefaultを実装している必要があります- 宣言されたパラメータリストは行ごとの引数リストです。
[villagesql::Type::Int]はaccumulateが受け取るもので、戻り値の型は結果関数が生成するものです agg_func!は、accumulate:の後にbuffer_size:とdeterministic:も(両方一緒に、この順序で)受け入れます
vsql_varargs — 可変長引数関数
それぞれが任意の数の引数を受け取る 4 つの VDF です。これらを合わせると、varargs_func! がサポートする 3 つの登録形式(prerun 付きの状態あり、prerun のみ、ベア)に加えて、カスタム型引数の検証をカバーします。
使用例:
#1 プレフィックスはステートメントごとの呼び出しカウンターで、1 つのステートメントの行にわたって増加します。
可変長引数の検証はすべて prerun が担う
可変長引数関数に対して、サーバーは引数のチェックを一切行いません。数も型もです。通常は、宣言されたシグネチャによってサーバーが不正な呼び出しをコードの実行前に拒否しますが、可変長引数関数にはそれがありません。prerun フックが拒否しなかったものはすべて行関数に到達します。 prerun は、どの行よりも前に 1 回だけ、呼び出しを拒否します。オプティマイザーが解決した引数の型を確認し、ステートメントを失敗させます。行関数は、それでも各値を処理しなければなりません。検証を通過した型の列でも、どの行でも NULL を保持し得るためです。 prerun による拒否は、ステートメントの初期化を失敗させます。arg_count はベア形式で登録されているため、引数ゼロの呼び出しも有効です。
実装
ファイル:src/lib.rs
prerun は PrerunArgs と、T が状態の型と一致する PrerunResult<T> を受け取ります。PrerunArgs::len() は引数の数で、type_at(i) は引数 i の型を ArgType として返します。
request_buffer_size を使い、args.len() に応じてバッファーサイズを設定してください。固定の buffer_size は引数の数に応じて大きくなれません。
ArgType は 4 つの述語 — is_int()、is_real()、is_str()、is_custom() — を公開しているため、すべての引数が行関数の処理できる形のいずれかである限り、prerun は異種の引数が混在する呼び出しを受け入れられます。describe は 3 つのスカラーの任意の組み合わせを受け入れ、それ以外を拒否します。
() なのは、この prerun が何も保持しないためです。検証とバッファーサイズの設定だけを行い、set_state は決して呼び出しません。
カスタム型の可変長引数
is_custom() だけでは、引数が何らかのカスタム型であることしかわかりません。custom_name() はどの型かを返すため、prerun は可変長引数の呼び出しを単一の型に制限できます。この拡張機能は point2d カスタム型を登録し、可変個の point2d 値を受け入れます。
InValue::Custom(b) をマッチさせ、他のカスタム型 VDF と同様にバイト列を自身でデコードします。
登録
describe、point_path、および point2d の encode/decode/compare は、上で str_join と rational について示したのと同じ InValue のマッチングとバイトエンコードのパターンに従います。完全なソースは Rust SDK リポジトリの examples/vsql_varargs/src/lib.rs を参照してください。
主要なパターン:
- パラメータリストの代わりに
[..]を書くことで、関数が可変長引数としてマークされます - 3 つの形式があり、それぞれ行関数のシグネチャが異なります。
state:+prerun:はfn(&mut State, &[InValue]) -> VdfReturn、prerun:のみとベア形式はどちらもfn(&[InValue]) -> VdfReturnです - ステートメントごとの状態を割り当てて破棄するのは
state:形式のみです - 戻り値の型は宣言されるため、可変なのは引数リストだけです
- 各形式は、末尾のペアとして
buffer_size:とdeterministic:も受け入れます point2dはhashを登録していません。これはオプションです。ORDER BYにはcompareだけで十分です
主要な実装パターン
テスト
4 つの例はすべて、C++ 拡張と同様に MTR (MySQL Test Runner) を使用します。--record を使用して期待される結果を生成または更新します。
次のステップ
Rust で拡張機能を作成する
SDK のインストール、ビルド、および extension! マクロ
Rust カスタム型
encode、decode、compare、hash の詳細
Rust API リファレンス
InValue、VdfReturn、およびマクロの API サーフェス
サンプルソース
4 つの例すべての完全なソース

