無料スクリプト配布のPHP.TO   PHPの実用的なtips PHPマニュアル MySQLマニュアル Apacheマニュアル PostgreSQLマニュアル マニュアル検索    

52.2. 外部データラッパのコールバックルーチン

FDWハンドラ関数は、以下で説明するコールバック関数へのポインタを含む、pallocされた FdwRoutine 構造体を返します。 スキャンに関連した関数は必須で、それ以外は省略可能です。

FdwRoutine 構造体は src/include/foreign/fdwapi.h で宣言されていますので、追加情報はそちらを参照してください。

52.2.1. 外部テーブルスキャンのためのFDWルーチン

void
GetForeignRelSize (PlannerInfo *root,
                   RelOptInfo *baserel,
                   Oid foreigntableid);

外部テーブルのリレーションサイズ見積もりを取得します。この関数は、ある外部テーブルをスキャンするクエリのプラン作成の開始時に呼び出されます。 root はそのクエリに関するプランナのグローバル情報です。 baserel はそのテーブルに関するプランナの情報です。そして、 foreigntableid はその外部テーブルの pg_class OIDです。( foreigntableid はプランナデータ構造体からも取得できますが、手間を省くために明示的に渡されます。)

この関数は、制約条件によるフィルタリングも考慮に入れた、そのテーブルスキャンが返すと見込まれる件数に baserel->rows を更新するべきです。 baserel->rows の初期値は固定のデフォルト見積もりなので、可能な限り置き換えられるべきです。この関数は、行の幅のよりよい見積もりを計算できるのであれば、 baserel->width を更新することも選択出来ます。

追加情報については 項52.4 を参照してください。

void
GetForeignPaths (PlannerInfo *root,
                 RelOptInfo *baserel,
                 Oid foreigntableid);

外部テーブル対するスキャンとしてありえるアクセスパスを作成します。 この関数はクエリのプラン作成中に呼び出されます。 引数は、先に呼ばれている GetForeignRelSize と同じです。

この関数は、少なくとも一つのアクセスパス( ForeignPath ノード)を作成して、それぞれのパスを baserel->pathlist に追加するために add_path を呼ばなければなりません。 ForeignPath ノードを構築するには create_foreignscan_path を使うことが推奨されています。 この関数は、たとえばソート済みの結果を表現する有効な pathkeys を持つパスのような複数のアクセスパスを作成することが出来ます。 それぞれのアクセスパスはコスト見積もりを含まねばならず、また意図した特定のスキャン方式を識別するのに必要なFDW固有の情報を持つことが出来ます。

追加情報については 項52.4 を参照してください。

ForeignScan *
GetForeignPlan (PlannerInfo *root,
                RelOptInfo *baserel,
                Oid foreigntableid,
                ForeignPath *best_path,
                List *tlist,
                List *scan_clauses);

選択された外部アクセスパスから ForeignScan プランノードを作成します。 この関数はクエリプラン作成の最後に呼び出されます。 引数は、 GetForeignRelSize と同じものに、選択された ForeignPath (事前に GetForeignPaths によって作成されたもの)と、そのプランノードによって出力されるターゲットリスト、およびそのプランノードで強制される条件句が追加されます。

この関数は ForeignScan プランノードを作成して返さなければなりません。 ForeignScan ノードを構築するには make_foreignscan を使うことが推奨されています。

追加情報については 項52.4 を参照してください。

void
BeginForeignScan (ForeignScanState *node,
                  int eflags);

外部テーブルスキャンの実行を開始します。 この関数はエグゼキュータの起動中に呼び出されます。 スキャンを開始できるようになる前に、あらゆる必要な初期化を実行するべきですが、実際のスキャンの実行を始めるべきではありません(それは最初の IterateForeignScan 呼び出しにおいて行われるべきです)。 ForeignScanState ノードは作成されていますが、その fdw_state フィールドはNULLのままです。 スキャンするテーブルの情報は、 ForeignScanState ノード(実際にはその先にある、 PlanForeignScan から返された FdwPlan 構造体へのポインタを含む、 ForeignScan プランノード)を通じてアクセス可能です。 eflags は、このプランノードに関するエグゼキュータの操作モードを表すフラグビットを含みます。

(eflags & EXEC_FLAG_EXPLAIN_ONLY) が真の場合、この関数は外部に見える処理を実行すべきではないことに注意してください。 ExplainForeignScan EndForeignScan 用にノード状態を有効にするのに必要とされる最小限のことだけをすべきです。

TupleTableSlot *
IterateForeignScan (ForeignScanState *node);

外部ソースから一行を取り出して、それをタプルテーブルスロットに入れて返します(この用途にはnodeの ScanTupleSlot を使うべきです)。 利用可能な行がない場合は、NULLを返します。 タプルテーブルスロット機構を使うと、物理タプルと仮想タプルのどちらでも返せます。 ほとんどの場合、パフォーマンスの観点から後者を選ぶのが良いでしょう。 この関数は、呼出しごとにリセットされる短命なメモリコンテキスト内で呼び出されることに注意してください。 より長命なストレージが必要な場合は、 BeginForeignScan でメモリコンテキストを作成するか、ノードの EState に含まれる es_query_cxt を使用してください。

返される行はスキャンされている外部テーブルのカラムシグネチャと一致しなければなりません。 不要なカラムを取り出さないように最適化することを選ぶなら、それらのカラム位置にNULLを入れるべきです。

PostgreSQL のエグゼキュータは返された行が外部テーブルの列に定義された NOT NULL 制約に違反しているかどうかは気にしません。しかし、プランナはそれに着目し、 NULL 値を含まないと宣言された列に NULL 値が現れた場合に不正なクエリ最適化をしてしまう場合があることに注意してください。 ユーザがあってはならないと宣言したのに NULL 値に遭遇した場合は(データ型が一致しなかった場合にする必要があるのと同様に)エラーを発生させるのが適切でしょう。

void
ReScanForeignScan (ForeignScanState *node);

先頭からスキャンを再開します。 スキャンが依存するいずれかのパラメータが値を変更しているかもしれないので、新しいスキャンが必ずしも厳密に同じ行を返すとは限らないことに注意してください。

void
EndForeignScan (ForeignScanState *node);

スキャンを終了しリソースを解放します。 通常、pallocされたメモリを解放することは重要ではありませんが、開いたファイルやリモートサーバへの接続などはクリーンアップするべきです。

52.2.2. 外部テーブル更新のためのFDWルーチン

もしFDWが更新可能な外部テーブルをサポートする場合、FDWのニーズと能力に応じて、以下のコールバック関数の一部または全てを提供する必要があります。

void
AddForeignUpdateTargets (Query *parsetree,
                         RangeTblEntry *target_rte,
                         Relation target_relation);

UPDATE DELETE の操作は、テーブルスキャン関数によって事前にフェッチされた行に対して実行されます。 FDWは、更新や削除の対象行を厳密に識別できるように行IDや主キー列の値といった追加情報を必要とするかもしれません。 それをサポートするために、この関数は UPDATE DELETE の間に外部テーブルから取得される列のリストに追加の隠された(または "ジャンクの" )ターゲット列を追加することができます。

これを実行するには、フェッチする追加の値の式を含む TargetEntry エントリを parsetree->targetList に追加します。 それぞれのエントリは resjunk = true とマークされなければならず、また実行時にエントリを識別できる異なる resname を持つ必要があります。 コアシステムがそのような名前のジャンク列を生成できるように、 ctid N wholerow N と一致する名前は使用しないでください。

この関数はプランナでなくリライタで呼ばれるので、利用可能な情報はプラン生成ルーチンで利用可能なものとは少し異なります。 parsetree UPDATE DELETE コマンドのパース木で、 target_rte target_relation は対象の外部テーブルを表します。

もし AddForeignUpdateTargets ポインターが NULL に設定されている場合は、追加のターゲット式は追加されません。 (FDWが行を識別するのに不変の主キーに依存するのであれば UPDATE は依然として実現可能かもしれませんが、 DELETE 操作を実装することは不可能になるでしょう。)

List *
PlanForeignModify (PlannerInfo *root,
                   ModifyTable *plan,
                   Index resultRelation,
                   int subplan_index);

外部テーブルに対する挿入、更新、削除に必要となる、追加のプラン生成アクションを実行します。 この関数は、更新処理を実行する ModifyTable プランノードに追加されるFDW固有の情報を生成します。この固有情報は List 形式でなければならず、また実行段階の間に BeginForeignModify に渡されます。

root はそのクエリに関するプランナのグローバル情報です。 plan fdwPrivLists フィールドを除いて完成している ModifyTable プランノードです。 resultRelation は対象の外部テーブルをレンジテーブルの添字で識別します。 subplan_index ModifyTable プランノードの対象がどれであるかを0始まりで識別します。この情報は plan->plans などの plan の下位構造を指定したい場合に使用してください。

追加情報は 項52.4 を参照してください。

もし AddForeignUpdateTargets ポインターが NULL に設定されている場合は、追加のプラン作成時処理は実行されず、 BeginForeignModify に渡される fdw_private リストはNILになります。

void
BeginForeignModify (ModifyTableState *mtstate,
                    ResultRelInfo *rinfo,
                    List *fdw_private,
                    int subplan_index,
                    int eflags);

外部テーブルへの変更操作の実行を開始します。 このルーチンはエグゼキュータの起動中に呼び出されます。 実際のテーブル変更に先立って必要なあらゆる初期化処理を実行する必要があります。 その後、各タプルが挿入、更新、削除されるように ExecForeignInsert ExecForeignUpdate ExecForeignDelete のいずれかが呼ばれます。

mtstate は実行されている ModifyTable プランノード全体の状態です。プランに関する全般的なデータと実行状態はこの構造体経由で利用可能です。 rinfo は対象の外部テーブルを表す ResultRelInfo 構造体です。( ResultRelInfo ri_FdwState フィールドはこの操作で必要となる固有の状態をFDWが格納するのに利用できます。) fdw_private はもしあれば PlanForeignModify で生成された固有データを含みます。 eflags は、このプランノードに関するエグゼキュータの操作モードを表すフラグビットを含みます。

(eflags & EXEC_FLAG_EXPLAIN_ONLY) が真の場合、この関数は外部に見える処理を実行すべきではないことに注意してください。 ExplainForeignModify EndForeignModify 用にノード状態を有効するのに必要な最小限のことだけを実行するべきです。

もし BeginForeignModify ポインターが NULL に設定されている場合は、エグゼキュータ起動時には追加処理は何も実行されません。

TupleTableSlot *
ExecForeignInsert (EState *estate,
                   ResultRelInfo *rinfo,
                   TupleTableSlot *slot,
                   TupleTableSlot *planSlot);

外部テーブルにタプルを一つ挿入します。 estate はそのクエリのグローバルな実行状態です。 rinfo は対象の外部テーブルを表す ResultRelInfo 構造体です。 slot には挿入されるタプルが含まれます。その行型定義は外部テーブルと一致します。 planSLot には ModifyTable プランノードのサブプランが生成したタプルが含まれます。追加の "ジャンク" 列を含みうる点において、 slot とは異なります。( planSlot は一般的に INSERT のケースにおいてはそれほど意味を持ちませんが、完全さのために提供されます。)

戻り値は実際に挿入されたデータ(例えばトリガー処理の結果などにより、提供されたデータとは異なるかもしれません)を含むスロットか、または(こちらも一般的にトリガーの結果)実際には挿入されなかった場合はNULLです。 渡された slot はこの用途に再利用可能です。

返却されたスロット内のデータは INSERT クエリが RETURNING 句を持っていた場合にのみ使われます。そのため、FDWは RETURNING 句の内容に応じて返却する列を一部にするか全てにするかを最適化する余地があります。しかしながら、処理成功を表すためになんらかのスロットは返却しなければなりません。さもないと、報告されるクエリの結果行数が誤った値になってしまいます。

もし ExecForeignInsert ポインターが NULL に設定されている場合は、外部テーブルへの挿入の試みはエラーメッセージとともに失敗します。

TupleTableSlot *
ExecForeignUpdate (EState *estate,
                   ResultRelInfo *rinfo,
                   TupleTableSlot *slot,
                   TupleTableSlot *planSlot);

外部テーブル内のタプルを一つ更新します。 estate はそのクエリのグローバルな実行状態です。 rinfo は対象の外部テーブルを表す ResultRelInfo 構造体です。 slot にはタプルの新しいデータが含まれます。その行型定義は外部テーブルと一致します。 planSLot には ModifyTable プランノードのサブプランが生成したタプルが含まれます。追加の "ジャンク" 列を含みうる点において、 slot とは異なります。実際、 AddForeignUpdateTargets が要求するジャンク列はこのスロットから利用可能です。

戻り値は実際に更新されたデータ(例えばトリガー処理の結果などにより、提供されたデータとは異なるかもしれません)を含むスロットか、または(こちらも一般的にトリガーの結果)実際には更新されなかった場合はNULLです。 渡された slot はこの用途に再利用可能です。

返却されたスロット内のデータは UPDATE クエリが RETURNING 句を持っていた場合にのみ使われます。そのため、FDWは RETURNING 句の内容に応じて返却する列を一部にするか全てにするかを最適化する余地があります。しかしながら、処理成功を表すためになんらかのスロットは返却しなければなりません。さもないと、報告されるクエリの結果行数が誤った値になってしまいます。

もし ExecForeignUpdate ポインターが NULL に設定されている場合は、外部テーブルへの更新の試みはエラーメッセージとともに失敗します。

	TupleTableSlot *
	ExecForeignDelete (EState *estate,
					   ResultRelInfo *rinfo,
					   TupleTableSlot *slot,
					   TupleTableSlot *planSlot);
	

外部テーブルからタプルを一つ削除します。 estate はそのクエリのグローバルな実行状態です。 rinfo は対象の外部テーブルを表す ResultRelInfo 構造体です。 slot にはタプルの新しいデータが含まれます。その行型定義は外部テーブルと一致します。 planSLot には ModifyTable プランノードのサブプランが生成したタプルが含まれます。実際、 AddForeignUpdateTargets が要求するジャンク列はこのスロットが運びます。ジャンク列は削除されるタプルを識別するために使用しなければなりません。

戻り値は実際に削除されたデータを含むスロットか、または(一般的にトリガーの結果)実際には削除されなかった場合はNULLです。 渡された slot は返却するタプルを保持する用途に利用可能です。

返却されたスロット内のデータは DELETE クエリが RETURNING 句を持っていた場合にのみ使われます。そのため、FDWは RETURNING 句の内容に応じて返却する列を一部にするか全てにするかを最適化する余地があります。しかしながら、処理成功を表すためになんらかのスロットは返却しなければなりません。さもないと、報告されるクエリの結果行数が誤った値になってしまいます。

もし ExecForeignDelete ポインターが NULL に設定されている場合は、外部テーブルからの削除の試みはエラーメッセージとともに失敗します。

void
EndForeignModify (EState *estate,
                  ResultRelInfo *rinfo);

テーブル更新を終えてリソースを解放します。pallocされたメモリの解放は通常重要ではありませんが、開いたファイルやリモートサーバへの接続はクリーンアップするべきです。

もし EndForeignModify ポインターが NULL に設定されている場合は、エグゼキュータ終了時には追加処理は何も実行されません。

int
IsForeignRelUpdatable (Relation rel);

指定された外部テーブルがどの更新処理をサポートしているかを報告します。 戻り値は、その外部テーブルがサポートする操作を表すルールイベント番号のビットマスクである必要があります。 UPDATE 用の (1 << CMD_UPDATE) = 4 INSERT 用の (1 << CMD_INSERT) = 8 DELETE 用の (1 << CMD_DELETE) = 16 といった CmdType 列挙値を使います。

もし IsForeignRelUpdatable ポインターが NULL に設定されていると、外部テーブルは ExecForeignInsert ExecForeignUpdate ExecForeignDelete を提供していると、それぞれ挿入、更新、削除をサポートしていると判断します。 この関数は、FDWが一部のテーブルについてのみ更新をサポートする場合にのみ必要です。 (そのような場合でも、この関数でチェックする代わりにクエリ実行関数でエラーにしても構いません。しかしながら、この関数は information_schema のビューの表示で更新可否を判定するのに使用されます。)

52.2.3. EXPLAIN のためのFDWルーチン

void
ExplainForeignScan (ForeignScanState *node,
                    ExplainState *es);

外部テーブルスキャンの追加の EXPLAIN 出力を表示します。 EXPLAIN 出力にフィールドを追加するために ExplainPropertyText や関連する関数を呼び出すことができます。 es の中のフラグフィールドは何を表示するかを決めるのに使用できます。また、 EXPLAIN ANALYZE の場合には、実行時統計情報を提供するために ForeignScanState ノードの状態を調べることができます。

もし ExplainForeignScan ポインターが NULL に設定されている場合は、 EXPLAIN 中に追加情報は表示されません。

void
ExplainForeignModify (ModifyTableState *mtstate,
                      ResultRelInfo *rinfo,
                      List *fdw_private,
                      int subplan_index,
                      struct ExplainState *es);

外部テーブル更新の追加の EXPLAIN 出力を表示します。 EXPLAIN 出力にフィールドを追加するために ExplainPropertyText や関連する関数を呼び出すことができます。 es の中のフラグフィールドは何を表示するかを決めるのに使用できます。また、 EXPLAIN ANALYZE の場合には、実行時統計情報を提供するために ForeignScanState ノードの状態を調べることができます。 最初の4つの引数は BeginForeignModify と同じです。

もし ExplainForeignModify ポインターが NULL に設定されている場合は、 EXPLAIN 中に追加情報は表示されません。

52.2.4. ANALYZE のためのFDWルーチン

bool
AnalyzeForeignTable (Relation relation,
                     AcquireSampleRowsFunc *func,
                     BlockNumber *totalpages);

この関数は ANALYZE が外部テーブルに対して実行されたときに呼び出されます。 もしFDWがこの外部テーブルの統計情報を収集できる場合は、そのテーブルからサンプル行を集める関数のポインタとページ単位でのテーブルサイズの見積もりをそれぞれ func totalpages に渡し true を返す必要があります。 そうでない場合は、 false を返します。

もしFDWが統計情報の収集をどのテーブルについてもサポートしない場合は、 AnalyzeForeignTable ポインターをNULLにすることもできます。

もし提供される場合は、サンプル収集関数はこのようなシグネチャを持つ必要があります。

int
AcquireSampleRowsFunc (Relation relation, int elevel,
                       HeapTuple *rows, int targrows,
                       double *totalrows,
                       double *totaldeadrows);

最大 targrows 行のランダムサンプルをテーブルから収集し、呼び出し元が提供する rows 配列に格納する必要があります。 実際に収集された行の数を返す必要があります。 さらに、テーブルに含まれる有効行と不要行の合計数の見積もりを出力パラメータの totalrows totaldeadrows に返す必要があります。(もしFDWが不要行という概念を持たない場合は totaldeadrows を0に設定してください。)


powered by SEO.CUG.NET