Skip to main content
このページでは、Rust SDK リポジトリにある参照拡張のうち 4 つを取り上げます。関数のみの最小限の例、算術演算、順序付け、ハッシュ化を備えた完全なカスタム型、集約関数、そして可変長引数関数です。リポジトリの examples/ ディレクトリには、サポートされているRustにおけるプレビュー機能ごとの例も 1 つずつ含まれています。 ソース: vsql-rust-sdkexamples/

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) として格納し、算術関数、順序付け、ハッシュ化を備えています。 使用例:

バイナリ格納形式

rational16 バイト (リトルエンディアン) を格納します。
  • バイト 0–7: 分子 (i64)
  • バイト 8–15: 分母 (i64)
値は常に、正の分母を持つ約分された形 (GCD = 1) で格納されます。

型システム関数

ファイル: 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_lengthencode() が返すバイト長と一致する必要があります
  • deterministic: true により、オプティマイザは定数呼び出しを畳み込むことができます

vsql_agg_sum — 集約関数

INT 列に対する SUM を再実装した集約 VDF です。集約に必要な 3 つのフック — clearaccumulate、および結果関数 — と、それぞれが同じアキュムレーターをどのように参照するかを示します。 使用例:
すべて NULL のグループを追加すると、アキュムレーターがグループ間で引き継がれるのではなく、リセットされることがわかります。

アキュムレーターのライフサイクル

アキュムレーターはステートメントごとに 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 による拒否は、ステートメントの初期化を失敗させます。
prerun を省略することは、すべての呼び出しを受け入れることを意味します。arg_count はベア形式で登録されているため、引数ゼロの呼び出しも有効です。

実装

ファイル: src/lib.rs prerun は PrerunArgs と、T が状態の型と一致する PrerunResult<T> を受け取ります。PrerunArgs::len() は引数の数で、type_at(i) は引数 i の型を ArgType として返します。
可変長引数では、prerun 内で 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 と同様にバイト列を自身でデコードします。

登録

describepoint_path、および point2dencode/decode/compare は、上で str_joinrational について示したのと同じ InValue のマッチングとバイトエンコードのパターンに従います。完全なソースは Rust SDK リポジトリexamples/vsql_varargs/src/lib.rs を参照してください。 主要なパターン:
  • パラメータリストの代わりに [..] を書くことで、関数が可変長引数としてマークされます
  • 3 つの形式があり、それぞれ行関数のシグネチャが異なります。state: + prerun:fn(&mut State, &[InValue]) -> VdfReturnprerun: のみとベア形式はどちらも fn(&[InValue]) -> VdfReturn です
  • ステートメントごとの状態を割り当てて破棄するのは state: 形式のみです
  • 戻り値の型は宣言されるため、可変なのは引数リストだけです
  • 各形式は、末尾のペアとして buffer_size:deterministic: も受け入れます
  • point2dhash を登録していません。これはオプションです。ORDER BY には compare だけで十分です

主要な実装パターン


テスト

4 つの例はすべて、C++ 拡張と同様に MTR (MySQL Test Runner) を使用します。
--record を使用して期待される結果を生成または更新します。

次のステップ

Rust で拡張機能を作成する

SDK のインストール、ビルド、および extension! マクロ

Rust カスタム型

encode、decode、compare、hash の詳細

Rust API リファレンス

InValue、VdfReturn、およびマクロの API サーフェス

サンプルソース

4 つの例すべての完全なソース