★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

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

FDWハンドラ関数は、以下のコールバック関数へのポインタを含む、pallocされたFdwRoutine構造体を返します。

FdwPlan *
PlanForeignScan (Oid foreigntableid,
                 PlannerInfo *root,
                 RelOptInfo *baserel);

外部テーブルへのスキャンの実行計画を作成します。 この関数はクエリの実行計画を作成するときに呼び出されます。 foreigntableidはその外部テーブルのpg_classのOIDです。 rootはそのクエリに関するプランナのグローバル情報で、baserelはこのテーブルに関するプランナの情報です。 この関数は、コストの見積もりに加えて、後で外部テーブルスキャンを実行するのに必要なFDWのプライベート情報を含む、pallocされた構造体を返さなければなりません。 (プライベート情報はcopyObjectがコピー方法を知っている形式で表現されていなければならないことに注意してください。)

rootbaserelに含まれる情報は、外部テーブルから取り出す情報を減らすために(結果としてコスト見積もりを減らすことに)使うことができます。 baserel->baserestrictinfoは、取り出す行を選別するのに使用できる制約条件(WHERE句)を含んでおり、特に興味深いものです。 (最終的な実行計画では制約条件を再度チェックするので、FDWでこれらの条件を適用しなければならないわけではありません。) baserel->reltargetlistは取り出す必要があるカラムを決定するのに使用できます。

この関数は、コスト見積もりを返すのに加えて、制約条件によるフィルタリングも考慮した、そのスキャンで返される想定行数にbaserel->rowsを更新すべきです。 baserel->rowsの初期値は単なるデフォルトの見積もりであり、可能であれば置き換えられるべきものです。 平均行長のより良い見積もりを算出できるのであれば、この関数でbaserel->widthを更新することを選択することもできます。

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

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

void
BeginForeignScan (ForeignScanState *node,
                  int eflags);

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

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

TupleTableSlot *
IterateForeignScan (ForeignScanState *node);

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

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

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

void
ReScanForeignScan (ForeignScanState *node);

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

void
EndForeignScan (ForeignScanState *node);

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

FdwRoutineFdwPlanの構造体型はsrc/include/foreign/fdwapi.hで宣言されているので、さらなる詳細はそちらを見て下さい。