拡張機能関数の作成
拡張機能関数は C++ で記述され、VEF に登録されます。SDK に完全にアクセスするには、単一のヘッダーをインクルードしてください:引数と結果の型
VDF のパラメータと結果は、型安全な引数型と結果型として渡されます。フレームワークは関数シグネチャからそれらを検出し、自動的に適応します —make_func の登録構文は変更されません。
引数型: IntArg, RealArg, StringArg, CustomArg — 各型は is_null() と value() を提供します。パラメータ化されたカスタム型の場合、CustomArgWith<P> はキャッシュされた解析済みの params 構造体を返す params() アクセサを追加します(Parameterized Types を参照)。
結果型: IntResult, RealResult, StringResult, CustomResult — 各型は set_null(), warning(msg), error(msg) を提供します。スカラー結果には set(value) も提供されます。バッファ結果には buffer() と set_length(len) が提供されます。StringResult にはさらに set(std::string_view) が提供され、ビューから最大 buffer().size() バイトをコピーして長さを一度に設定します。パラメータ化されたカスタム型の場合、CustomResultWith<P> は params() アクセサを追加します。
Span 型: バイト指向の引数型と結果型における value() と buffer() は vsql::Span<T> を返します — data(), size(), empty(), begin()/end(), operator[] を持つ、連続した T の範囲に対する非所有ビューです。C++20 では std::span<T> のエイリアスであり、C++17 では SDK が最小限の互換実装を提供するため、どちらの標準でも同じコードがコンパイルされます。<villagesql/vsql.h> を介して利用可能です。
warning(msg) は行に対して SQL NULL を返し、SQL 警告を追加します。厳格モード(STRICT_TRANS_TABLES)では、MySQL はこれを INSERT/UPDATE 時のステートメントエラーに昇格させるため、厳格なコンテキストでは error(msg) と同様に動作します。エンコード関数で解析できない文字列など、回復可能な不正な入力に使用してください。破損した保存データや、続行が安全でないあらゆる条件には error(msg) を使用してください。両方のメッセージは必要に応じてサーバーの内部エラーバッファに収まるように切り捨てられます。
スカラーの例 — 2 つの整数を加算:
StringResult と CustomResult の場合、buffer() に書き込み、その後書き込んだバイト数で set_length() を呼び出します。buffer().size() が最大容量です。
カスタム型を返す VDF(returns(CUSTOM(MYTYPE)))の場合、サーバーは結果バッファのサイズを解決された戻り型の persisted_length に自動的に合わせます — 拡張機能作者はこの場合、関数ビルダーで .buffer_size(...) を宣言する必要はありません。prerun がバッファをさらに拡張する場合、その大きなサイズは保持されます。これにより、例えば SVECTOR::from_string('[…1024 floats…]') が結果バッファの領域不足なしでワイドベクトルをエンコードできます。
同じ拡張機能内の関数間で異なるスタイルを使用できます — 各関数のスタイルはそれぞれのシグネチャによって決定されます。
集計 VDF
集計 VDF は各GROUP BY グループ内の行にわたって状態を蓄積し、SQL の SUM や COUNT のようにグループごとに 1 つの結果を返します。登録には make_aggregate_func<State, &result_fn>("name") を使用します。State 型はグループごとの蓄積バッファであり、prerun と postrun はそれを割り当てて削除するために自動生成されます。
結果関数は void(const State&, ResultType) のシグネチャを持つ必要があり、ResultType は IntResult, RealResult, StringResult, CustomResult, または CustomResultWith<P> のいずれかです。値を返すには out.set(value) を、SQL NULL を返すには out.set_null() を呼び出します。
.clear<>() と .accumulate<>() の両方が必須です。ビルダーはこれをコンパイル時に(build() を介して)強制し、サーバーは INSTALL EXTENSION 時に再度検証します — clear は状態をリセットし、accumulate は行を折りたたみ、結果関数は最終状態を読み取ります。
make_aggregate_func<State, &result_fn>()はprerunとpostrunを自動生成します(Stateの値初期化と削除)。.clear<&fn>()はvoid(State&)のリセット関数を登録します。.accumulate<&fn>()はvoid(State&, TypedArgs...)の折りたたみ関数を登録します。TypedArgsは関数シグネチャ(IntArg,StringArgなど)から推論されます。- 結果型(
IntResult,RealResultなど)は結果関数のシグネチャから推論されます。
StringResult の集計 VDF はテキストを返します。結果は utf8mb4_bin の文字セットと照合順序を報告するため、クライアントは 16 進数ではなく文字として表示します — スカラー VDF の STRING パスと同じです。また、.max_result_length(n) も同様に適用し、マテリアライズされた集計結果(GROUP BY/DISTINCT の一時テーブル、CREATE TABLE ... SELECT、または UNION)のサイズを設定して引数幅で切り捨てられないようにします。サイズ設定のルールと上限については Custom Buffer Sizes を参照してください。
ステートメントごとの状態(Prerun と Postrun)
一部の VDF では、単一のクエリがアクセスするすべての行にわたる状態が必要です — 呼び出しカウンター、キャッシュされた結果、オープンリソースなど。prerun フックで割り当て、VDF 本体からアクセスし、postrun フックで解放します。両方のフックはステートメントごとに 1 回実行され、VDF 本体は行ごとに 1 回実行されます。.prerun<&Hook>() と .postrun<&Hook>() で登録します。必要なシグネチャは次の通りです:
状態を保存するには
PrerunResult::set_user_data(void*) を使用し、解放するには PostrunArgs::delete_state<T>() を使用します。prerun が set_user_data(new T{}) を呼び出す場合、postrun は 必ず delete_state<T>() を呼び出す必要があります — SDK は自動解放しません。
PrerunArgs::type_at(i) は、行が読み込まれる前に各引数の宣言された SQL 型を公開します。返される PrerunArgType 上の述語 is_int(), is_real(), is_str(), is_custom() は列型を反映します。これを prerun で引数型の検証に使用するか、結果バッファのサイズ設定に PrerunResult::request_buffer_size(n) を呼び出します。
可変長引数 VDF
可変長引数 VDF は、任意の SQL 型の任意の数の引数を受け入れます。func ビルダーで.varargs() を宣言し、これは .no_params() および .param(TYPE) と排他です。本体は通常の固定引数型の代わりに vsql::VarArgs 引数を受け取ります。
フレームワークは可変長引数 VDF の引数カウントや型を検証できません。すべての可変長引数登録には、不正な入力時に PrerunResult::error() を呼び出すか、結果バッファのサイズ設定に PrerunResult::request_buffer_size(n) を呼び出す prerun フックをペアにしてください。
範囲 for ループで引数を反復処理します。各 AnyArg 要素は値を読み取る前に型チェックが必要です:
いずれのアクセサを呼び出す前にも
is_null() をチェックしてください — 4 つすべてで null 引数に対する動作は未定義です。
VEF_GENERATE_REGISTRATION
VEF_GENERATE_REGISTRATION は拡張機能登録を実行しますが extern "C" エントリポイントを定義しない内部ヘルパー _vef_do_register() を作成します。テストビルドで登録後に記述子をパッチするなど、vef_register の動作をカスタマイズする必要がある場合に使用してください。通常の拡張機能には代わりに VEF_GENERATE_ENTRY_POINTS を使用します。
カスタム型演算
型演算ビルダーの完全なリファレンス — エンコード、デコード、比較、ハッシュ、組み込みデフォルト、およびパラメータ化された型 — については、Type Operations を参照してください。プレビュー機能
以下の VEF 機能は、オプトインのプレビューヘッダーとして利用可能です。ABI と API はまだ活発に開発中です。完全なリファレンスについては、Preview Capabilities を参照してください。- 拡張機能システム変数 — Preview Capabilities → System Variables
- 拡張機能ステータス変数 — Preview Capabilities → Status Variables
- キーリングアクセス — Preview Capabilities → Keyring Access
- 列ストレージ — Preview Capabilities → Column Storage
拡張機能登録メタデータの検査
INFORMATION_SCHEMA.EXTENSION_REGISTRATION は、読み込まれた各拡張機能のメモリ内 VEF 登録構造体を JSON ドキュメントとして公開します。INSTALL EXTENSION 後にサーバーが拡張機能の関数、型、システム変数を正しくパースしたことを確認するために使用します。
関連資料
- Creating Extensions in C++ — エンドツーエンドのビルド手順、CMake セットアップ、およびインストール
- C++ Testing — ローカル開発サーバー、MTR、および失敗のデバッグ
- Type Operations — エンコード、デコード、比較、ハッシュ、パラメータ化された型
- C++ API Reference — VDF 契約、null 処理、およびバッファサイズ設定
- Extension Architecture — ライフサイクル、Victionary キャッシュ、パフォーマンスパターン、およびセキュリティモデル

