Skip to main content
このガイドは、C++ VDF 実装を作成するための詳細なリファレンスです。エンドツーエンドのビルド手順をカバーする Creating Extensions in C++ と、テストと反復のループをカバーする C++ Testing の補完資料です。
VEF Protocol 3 は v0.0.4 で安定版となりました。Protocol 4 は開発中で、オプトイン形式の dev ABI ヘッダー(-DVSQL_USE_DEV_ABI=ON)経由でのみ利用可能です。古い Protocol 2 に対してビルドされた拡張機能はサーバーによって拒否され、再ビルドが必要です。

拡張機能関数の作成

拡張機能関数は 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 つの整数を加算:
バイナリの例 — カスタム型バッファをインプレースで変換:
StringResultCustomResult の場合、buffer() に書き込み、その後書き込んだバイト数で set_length() を呼び出します。buffer().size() が最大容量です。 カスタム型を返す VDF(returns(CUSTOM(MYTYPE)))の場合、サーバーは結果バッファのサイズを解決された戻り型の persisted_length に自動的に合わせます — 拡張機能作者はこの場合、関数ビルダーで .buffer_size(...) を宣言する必要はありません。prerun がバッファをさらに拡張する場合、その大きなサイズは保持されます。これにより、例えば SVECTOR::from_string('[…1024 floats…]') が結果バッファの領域不足なしでワイドベクトルをエンコードできます。 同じ拡張機能内の関数間で異なるスタイルを使用できます — 各関数のスタイルはそれぞれのシグネチャによって決定されます。

集計 VDF

集計 VDF は各 GROUP BY グループ内の行にわたって状態を蓄積し、SQL の SUMCOUNT のようにグループごとに 1 つの結果を返します。登録には make_aggregate_func<State, &result_fn>("name") を使用します。State 型はグループごとの蓄積バッファであり、prerunpostrun はそれを割り当てて削除するために自動生成されます。 結果関数は void(const State&, ResultType) のシグネチャを持つ必要があり、ResultTypeIntResult, 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>()prerunpostrun を自動生成します(State の値初期化と削除)。
  • .clear<&fn>()void(State&) のリセット関数を登録します。
  • .accumulate<&fn>()void(State&, TypedArgs...) の折りたたみ関数を登録します。TypedArgs は関数シグネチャ(IntArg, StringArg など)から推論されます。
  • 結果型(IntResult, RealResult など)は結果関数のシグネチャから推論されます。
NULL を返さないカウンターの場合、プレーンな状態型を使用します:
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 引数を受け取ります。
可変長引数の登録には VEF Protocol 3 が必要です。古いサーバーはインストール時に拡張機能を拒否します。
フレームワークは可変長引数 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 を参照してください。

拡張機能登録メタデータの検査

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 キャッシュ、パフォーマンスパターン、およびセキュリティモデル