本章は、PostgreSQLのコアシステムと、テーブルの格納を制御するテーブルアクセスメソッドとのインタフェースを説明します。 コアシステムはこのアクセスメソッドについて、ここで指定されたことのみを把握しています。これにより、追加コードを記述することで全く新しいアクセスメソッド種類を開発することができます。
各テーブルアクセスメソッドはpg_amシステムカタログの行で記述されます。
pg_amのエントリではテーブルアクセスメソッドの名前とハンドラ関数を指定します。
これらのエントリはSQLコマンドCREATE ACCESS METHODとDROP ACCESS METHODを使って、作成および削除することができます。
テーブルアクセスメソッドのハンドラ関数はinternal型の引数を一つ取り、table_am_handler疑似型を返すように宣言されなければなりません。
この引数はハンドラ関数がSQLコマンドから直接呼び出されるのを防ぐためだけのダミーの値です。
拡張SQLスクリプトファイルでテーブルアクセスメソッドのハンドラを作成する方法を以下に示します。
CREATE OR REPLACE FUNCTION my_tableam_handler(internal) RETURNS table_am_handler AS 'my_extension', 'my_tableam_handler' LANGUAGE C STRICT; CREATE ACCESS METHOD myam TYPE TABLE HANDLER my_tableam_handler;
関数の結果はTableAmRoutine型の構造体へのポインタでなければならず、そこにはテーブルアクセスメソッドを使用するためにコアコードが知る必要のあるすべてのことが含まれます。
戻り値は、サーバの存続期間中は有効である必要があります。
これは通常、グローバルスコープでstatic const変数として定義することによって達成されます。
テーブルアクセスメソッドのハンドラを含むソースファイルは次のようになります。
#include "postgres.h"
#include "access/tableam.h"
#include "fmgr.h"
PG_MODULE_MAGIC;
static const TableAmRoutine my_tableam_methods = {
.type = T_TableAmRoutine,
/* Methods of TableAmRoutine omitted from example, add them here. */
};
PG_FUNCTION_INFO_V1(my_tableam_handler);
Datum
my_tableam_handler(PG_FUNCTION_ARGS)
{
PG_RETURN_POINTER(&my_tableam_methods);
}
アクセスメソッドのAPI構造体とも呼ばれるTableAmRoutine構造体は、コールバックを使ってアクセスメソッドの振る舞いを定義します。
これらのコールバックは通常のC関数へのポインタで、SQLレベルでは見ることも呼び出すこともできません。
全てのコールバックとその振る舞いは、TableAmRoutine構造体(とコールバックの必要性を説明する構造体内のコメント)で定義されます。
たいていのコールバックはラッパー関数を持ち、これらはテーブルアクセスメソッドの(開発者ではなく)使用者の立場でドキュメントに記載されています。
詳細はsrc/include/access/tableam.hファイルを参照してください。
アクセスメソッドを実装するには開発者は通常、タプルテーブルスロットのAM固有の型を実装する必要があります(src/include/executor/tuptable.hを参照してください)。
これはアクセスメソッド外のコードが、AMのタプルへの参照を保持できるようにして、そのタプルの列にアクセスできるようにするものです。
今のところAMが実際にデータを格納する方法は全く制限されていません。 例えば、postgresの共有バッファキャッシュを使うことも、必須ではありませんが、可能です。 使う場合、おそらく66.6に記述されたPostgreSQLの標準ページレイアウトを使うには有意義でしょう。
現在のテーブルアクセスメソッドAPIのそれなりに大きい制約は、AMが更新および/またはインデックスに対応したい場合、各タプルがブロック番号とアイテム番号から成るタプル識別子(TID)を持つ必要があることです(66.6も参照してください)。
TIDsの下位要素が、例えばheapに対して持つのと同じ意味を持つことは、厳密には必要ありません。しかし、ビットマップスキャン対応(これは任意です)を望むなら、ブロック番号は局所性を備える必要があります。
クラッシュ安全性のために、AMはpostgresのWAL、あるいは、カスタム実装を使うことができます。 WALを選んだ場合、汎用WALレコードを利用するか、カスタムWALリソースマネージャを実装することができます。
異なるテーブルアクセスメソッドが単一トランザクション内でアクセスできるという類のトランザクション対応を実装するには、おそらくsrc/backend/access/transam/xlog.cの仕組みと注意深く統合することが必要でしょう。
新テーブルアクセスメソッドの開発者は、実装の詳細について、src/backend/access/heap/heapam_handler.cにある既存のheapの実装を参照できます。