FDWハンドラ関数は、以下で説明するコールバックの関数ポインタを含む、pallocされたFdwRoutine
構造体を返します。
スキャンに関連した関数は必須で、それ以外は省略可能です。
FdwRoutine
構造体はsrc/include/foreign/fdwapi.h
で宣言されていますので、追加情報はそちらを参照してください。
void GetForeignRelSize(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid);
外部テーブルのリレーションサイズ見積もりを取得します。
この関数は、ある外部テーブルをスキャンする問い合わせのプラン作成の開始時に呼び出されます。
root
はその問い合わせに関するプランナのグローバル情報です。
baserel
はそのテーブルに関するプランナの情報です。
そして、foreigntableid
はその外部テーブルのpg_class
OIDです。
(foreigntableid
はプランナデータ構造体からも取得できますが、手間を省くために明示的に渡されます。)
この関数は、検索条件によるフィルタリングも考慮に入れた、そのテーブルスキャンが返すと見込まれる件数にbaserel->rows
を更新するべきです。
baserel->rows
の初期値は固定のデフォルト見積もりなので、可能な限り置き換えられるべきです。この関数は、行の幅のよりよい見積もりを計算できるのであれば、baserel->width
を更新することも選択出来ます。
(初期値は列の型と最後に実行されたANALYZE
から計測された平均列幅に基づいています。)
また、外部テーブルの総行数の見積もりをより正しく計算できる場合、この関数は、baserel->tuples
を更新しても構いません。
(初期値はpg_class
.reltuples
で、最後に実行されたANALYZE
によって確認された総行数です。
もしこの外部テーブルにANALYZE
が実行されていない場合は、-1
になります。)
追加情報については57.4を参照してください。
void GetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid);
外部テーブル対するスキャンとして可能なアクセスパスを作成します。
この関数は問い合わせのプラン作成中に呼び出されます。
引数は、先に呼ばれているGetForeignRelSize
と同じです。
この関数は、少なくとも一つのアクセスパス(ForeignPath
ノード)を作成して、それぞれのパスをbaserel->pathlist
に追加するためにadd_path
を呼ばなければなりません。
ForeignPath
ノードを構築するにはcreate_foreignscan_path
を使うことが推奨されています。
この関数は、たとえばソート済みの結果を表現する有効なpathkeys
を持つパスのような複数のアクセスパスを作成することが出来ます。
それぞれのアクセスパスはコスト見積もりを含まねばならず、また意図した特定のスキャン方式を識別するのに必要なFDW固有の情報を持つことが出来ます。
追加情報については57.4を参照してください。
ForeignScan * GetForeignPlan(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan);
選択された外部アクセスパスからForeignScan
プランノードを作成します。
この関数は問い合わせのプラン作成の最後に呼び出されます。
引数は、GetForeignRelSize
と同じものに、選択されたForeignPath
(事前にGetForeignPaths
、GetForeignJoinPaths
またはGetForeignUpperPaths
によって作成されたもの)、そのプランノードによって出力されるターゲットリスト、そのプランノードで強制される条件句、およびRecheckForeignScan
が実行する再検査で使用されるForeignScan
の外側のサブプランが追加されます。
(パスがベースリレーションではなく結合のためのものの場合、foreigntableid
はInvalidOid
になります。)
この関数はForeignScan
プランノードを作成して返さなければなりません。ForeignScan
ノードを構築するにはmake_foreignscan
を使うことが推奨されています。
追加情報については57.4を参照してください。
void BeginForeignScan(ForeignScanState *node, int eflags);
外部テーブルスキャンの実行を開始します。
この関数はエクゼキュータの起動中に呼び出されます。
スキャンを開始できるようになる前に、あらゆる必要な初期化を実行するべきですが、実際のスキャンの実行を始めるべきではありません(それは最初のIterateForeignScan
呼び出しにおいて行われるべきです)。
ForeignScanState
ノードは作成されていますが、そのfdw_state
フィールドはNULLのままです。
スキャンするテーブルの情報は、ForeignScanState
ノード(特に、その先にあるGetForeignPlan
から提供されたFDWプライベート情報を含む、ForeignScan
プランノード)を通じてアクセス可能です。
eflags
は、このプランノードに関するエクゼキュータの操作モードを表すフラグビットを含みます。
(eflags & EXEC_FLAG_EXPLAIN_ONLY)
が真の場合、この関数は外部に見える処理を実行すべきではないことに注意してください。
ExplainForeignScan
やEndForeignScan
用にノード状態を有効にするのに必要とされる最小限のことだけをすべきです。
TupleTableSlot * IterateForeignScan(ForeignScanState *node);
外部ソースから一行を取り出して、それをタプルテーブルスロットに入れて返します(この用途にはノードのScanTupleSlot
を使うべきです)。
利用可能な行がない場合は、NULLを返します。
タプルテーブルスロット機構を使うと、物理タプルと仮想タプルのどちらでも返せます。
ほとんどの場合、パフォーマンスの観点から後者を選ぶのが良いでしょう。
この関数は、呼出しごとにリセットされる短命なメモリコンテキスト内で呼び出されることに注意してください。
より長命なストレージが必要な場合は、BeginForeignScan
でメモリコンテキストを作成するか、ノードのEState
に含まれるes_query_cxt
を使用してください。
返される行は、ターゲットリストfdw_scan_tlist
が提供されたなら、それとマッチしなければならず、提供されていない場合はスキャンされている外部テーブルの行型とマッチしなければなりません。
不要な列を取り出さないように最適化することを選ぶなら、それらの列の位置にNULLを入れるか、あるいはそれらの列を除いたfdw_scan_tlist
リストを生成するべきです。
PostgreSQLのエクゼキュータは返された行が外部テーブルに定義された制約に違反しているかどうかは気にしません。 しかし、プランナはそれに着目するので、宣言された制約に反する行が外部テーブル上にあった場合に、不正な最適化をするかもしれません。 ユーザが制約が成り立つと宣言したのに制約に違反した場合は(データ型が一致しなかった場合にする必要があるのと同様に)エラーを発生させるのが適切でしょう。
void ReScanForeignScan(ForeignScanState *node);
先頭からスキャンを再開します。 スキャンが依存するいずれかのパラメータが値を変更しているかもしれないので、新しいスキャンが必ずしも厳密に同じ行を返すとは限らないことに注意してください。
void EndForeignScan(ForeignScanState *node);
スキャンを終了しリソースを解放します。 通常、pallocされたメモリを解放することは重要ではありませんが、たとえば開いたファイルやリモートサーバへの接続などはクリーンアップするべきです。
FDWが外部テーブルの結合を(両方のテーブルのデータをフェッチして、ローカルで結合するのでなく)リモートで実行することをサポートする場合、次のコールバック関数を提供します。
void GetForeignJoinPaths(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra);
同じ外部サーバにある2つ(またはそれ以上)の外部テーブルの結合のための可能なアクセスパスを作成します。
このオプション関数は、問い合わせの計画時に呼び出されます。
GetForeignPaths
と同じく、この関数は提供されたjoinrel
のためのForeignPath
パスを生成し(そのためにcreate_foreign_join_path
を使用します)、add_path
を呼んで、それらのパスを結合のために考慮されるパスの集合に追加します。
しかし、GetForeignPaths
とは異なり、この関数が少なくとも1つのパスの作成に成功することは必要ではありません。
なぜなら、ローカルの結合を含んだパスはいつでも可能だからです。
この関数は、同じ結合のリレーションに対して、内側と外側のリレーションの異なる組み合わせで繰り返し呼び出されることに注意して下さい。 同じ作業の繰り返しを最小化することはFDWの責任です。
ForeignPath
パスが結合のために選択されると、それは結合プロセス全体を代表することになり、構成テーブルとその関連の結合のために生成されたパスは使われなくなります。
結合パスの以降の処理は、単一の外部テーブルをスキャンするパスとほぼ同様に進みます。
1つの相違点は、結果として作られるForeignScan
計画ノードのscanrelid
が0にセットされるべき、ということで、これはそれが表現する単一のリレーションがないためです。
その代わりに、ForeignScan
ノードのfs_relids
フィールドが結合されるリレーションの集合を表します。
(後者のフィールドはコアのプランナのコードによって自動的にセットされるので、FDWによって設定される必要はありません。)
他の相違点は、リモートの結合についての列リストがシステムカタログにはないため、FDWはfdw_scan_tlist
に適切なTargetEntry
ノードのリストを入れて、実行時に返されるタプル内の列の集合を表すようにしなければならないということです。
追加情報については57.4を参照してください。
FDWがリモート集約など、リモートでのスキャン/結合後の処理をサポートする場合、次のコールバック関数を提供します。
void GetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage, RelOptInfo *input_rel, RelOptInfo *output_rel, void *extra);
上位リレーション処理のための、ありうるアクセスパスを作成します。上位リレーションはプランナ用語で、ウィンドウ関数、ソート、テーブル更新など、全てのスキャン/結合後の問い合わせのことです。
この省略可能な関数は問い合わせのプラン作成時に呼ばれます。
今のところ、これは問い合わせに含まれる全てのベースリレーションが同じFDWに属する場合だけ呼ばれます。
この関数では、FDWがどのようにリモートで実行するか分かっている全てのスキャン/結合後の処理にForeignPath
パスを生成し(そのためにcreate_foreign_upper_path
を使用します)、それらパスを指定された上位リレーションに加えるためにadd_path
を呼び出してください。
GetForeignJoinPaths
の時と同様に、この関数が何らかのパス作成に成功する必要はありません。なぜなら、ローカル処理を含んでいるパスはいつでも可能だからです。
stage
パラメータはどのスキャン/結合後の処理が現在考慮されているかを定めます。
output_rel
は本処理の計算方法をあらわすパスを受け取るであろう上位リレーションで、input_rel
は本処理への入力をあらわすリレーションです。
extra
パラメータは追加の詳細を指定し、今のところUPPERREL_PARTIAL_GROUP_AGG
とUPPERREL_GROUP_AGG
に対して指定できて、この場合はGroupPathExtraData
構造体へのポインタです。
さらにUPPERREL_FINAL
に対しても指定できて、この場合はFinalPathExtraData
構造体へのポインタです。
(注意:これらの処理は外部で実行されると考えられるため、output_rel
に加えられるForeignPath
パスは、一般的にinput_rel
のパスへの直接の依存を全く持たないでしょう。
しかしながら、手前の処理段階のために以前に生成されたパスを検査することは、冗長なプラン作成活動を回避するのに役立ちます。)
追加情報については57.4を参照してください。
もしFDWが更新可能な外部テーブルをサポートする場合、FDWのニーズと能力に応じて、以下のコールバック関数の一部または全てを提供する必要があります。
void AddForeignUpdateTargets(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation);
UPDATE
とDELETE
の操作は、テーブルスキャン関数によって事前にフェッチされた行に対して実行されます。
FDWは、更新や削除の対象行を厳密に識別できるように行IDや主キー列の値といった追加情報を必要とするかもしれません。
それをサポートするために、この関数はUPDATE
やDELETE
の間に外部テーブルから取得される列のリストに追加の隠された(または「ジャンクの」)ターゲット列を追加することができます。
それを行うには、必要な追加の値を表すVar
を作成し、それをジャンク列の名前とともにadd_row_identity_var
に渡します。(複数の列が必要な場合は、これを二回以上実行できます。)
必要とするそれぞれのVar
に個別のジャンク列名を選択する必要があります。ただし、Var
がvarno
フィールドを除いて同一である場合は、列名を共有することができるのでそうすべきです。
コアシステムは、テーブルのtableoid
列をジャンク列名tableoid
に、ctid
またはctid
をN
ctid
に使用し、vartype
= RECORD
と記された行全体のVar
をwholerow
に、vartype
を記された行全体のVar
をwholerow
使用しており、テーブルで宣言された行型が同じです。
できる限りこれらの名前を再利用してください(プランナは同一のジャンク列に対する重複したリクエストを結合します)。
もしこれらとは別の種類のジャンク列が必要なら、他のFDWとの衝突を避けるために拡張子名をプレフィックスとした名前を選ぶのが賢明かもしれません。
N
もし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
ノードのターゲットリレーションごとのサブ構造にインデックスを付けたい場合に使用してください。
追加情報は57.4を参照してください。
もしPlanForeignModify
ポインタがNULL
に設定されている場合は、追加のプラン作成時処理は実行されず、BeginForeignModify
に渡されるfdw_private
リストはNILになります。
void BeginForeignModify(ModifyTableState *mtstate, ResultRelInfo *rinfo, List *fdw_private, int subplan_index, int eflags);
外部テーブルへの変更操作の実行を開始します。
このルーチンはエクゼキュータの起動中に呼び出されます。
実際のテーブル変更に先立って必要なあらゆる初期化処理を実行する必要があります。
その後、各タプルが挿入、更新、削除されるようにExecForeignInsert/ExecForeignBatchInsert
、ExecForeignUpdate
、ExecForeignDelete
のいずれかが呼ばれます。
mtstate
は実行されているModifyTable
プランノード全体の状態です。プランに関する全般的なデータと実行状態はこの構造体経由で利用可能です。
rinfo
は対象の外部テーブルを表すResultRelInfo
構造体です。
(ResultRelInfo
のri_FdwState
フィールドはこの操作で必要となる固有の状態をFDWが格納するのに利用できます。)
fdw_private
は、もしあればPlanForeignModify
で生成された固有データを含みます。
subplan_index
は、これがModifyTable
プランノードのどのターゲットであるかを識別します。
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
句を持っているか、WITH CHECK OPTION
を伴うビューに影響を及ぼす場合、もしくは、外部テーブルがAFTER ROW
トリガを持っていた場合にのみ使われます。
トリガは全列を必要としますが、FDWはRETURNING
句やWITH CHECK OPTION
の制約の内容に応じて、返却する列を一部にするかすべてにするかを最適化する余地があります。
それとは関係なく、処理成功を表すためになんらかのスロットは返却しなければなりません。さもないと、報告される問い合わせの結果行数が誤った値になってしまいます。
もしExecForeignInsert
ポインタがNULL
に設定されている場合は、外部テーブルへの挿入の試みはエラーメッセージとともに失敗します。
この関数は外部テーブルパーティションに転送対象のタプルを挿入する際、あるいはCOPY FROM
を外部テーブルに対して実行する際にも呼び出されることに注意してください。
COPY FROM
の場合、INSERT
とはこの関数の呼び出され方は異なります。
FDWがそれをサポートすることを可能にする以下で説明するコールバック関数をご覧ください。
TupleTableSlot ** ExecForeignBatchInsert(EState *estate, ResultRelInfo *rinfo, TupleTableSlot **slots, TupleTableSlot **planSlots, int *numSlots);
外部テーブルに一括で複数のタプルを挿入します。
slots
とplanSlots
が複数のタプルを含むことと*numSlots
がそれらの配列のタプルの数を指定すること以外はExecForeignInsert
とパラメータは同じです。
戻り値は実際に挿入されたデータを含んだスロットの配列です。(これは例えばトリガー実行の結果として、提供された結果と異なるかもしれません。)
渡されたslots
は、この目的のために再利用できます。
挿入に成功したタプルの数は、*numSlots
に返されます。
返却されたスロット内のデータはINSERT
文がビューWITH CHECK OPTION
を含む場合、または外部テーブルにAFTER ROW
トリガーがある場合にのみ、使用されます。
トリガーはすべての列を必要としますが、FDWはWITH CHECK OPTION
制約の内容に応じて、一部またはすべての列を返さないように最適化することを選択することができます。
ExecForeignBatchInsert
またはGetForeignModifyBatchSize
ポインタにNULL
が設定された場合、外部テーブルにはExecForeignInsert
を使って挿入を試みます。
この関数はRETURNING
句をもつINSERT
の場合、使用されません。
この関数は、ルーティングされたタプルを外部テーブルパーティションに挿入するときにも呼び出されることに注意してください。 FDWがそれをサポートすることを可能にしている後述のコールバック関数を参照してください。
int GetForeignModifyBatchSize(ResultRelInfo *rinfo);
指定された外部テーブルに対して、単一のExecForeignBatchInsert
呼び出しが処理できる最大のタプル数を報告します。
エグゼキュータは、最大で指定された数のタプルをExecForeignBatchInsert
に渡します。
rinfo
には、対象の外部テーブルを記述したResultRelInfo
構造体を指定します。
FDWは、ユーザーがこの値またはハードコードされた値を設定するための外部サーバや外部テーブルオプションを提供することを想定しています。
ExecForeignBatchInsert
またはGetForeignModifyBatchSize
ポインタにNULL
が設定された場合、外部テーブルにはExecForeignInsert
を使って挿入を試みます。
TupleTableSlot * ExecForeignUpdate(EState *estate, ResultRelInfo *rinfo, TupleTableSlot *slot, TupleTableSlot *planSlot);
外部テーブル内のタプルを一つ更新します。
estate
はその問い合わせのグローバルな実行状態です。
rinfo
は対象の外部テーブルを表すResultRelInfo
構造体です。
slot
にはタプルの新しいデータが含まれます。その行型定義は外部テーブルと一致します。
planSlot
にはModifyTable
プランノードのサブプランが生成したタプルが含まれます。
slot
とは異なり、このタプルは問い合わせによって変更された列の新しい値のみを含むので、planSlot
にインデックスを付けるために外部テーブルの属性番号に依存しないようにしましょう。
また、planSlot
は通常、追加の「ジャンク」列を含んでいます。
特に、AddForeignUpdateTargets
によって要求されたジャンク列は、このスロットから利用できるようになります。
戻り値は実際に更新されたデータ(例えばトリガー処理の結果などにより、提供されたデータとは異なるかもしれません)を含むスロットか、または(こちらも一般的にトリガーの結果)実際には更新されなかった場合はNULLです。
渡されたslot
はこの用途に再利用可能です。
返却されたスロット内のデータはUPDATE
文がRETURNING
句を持っているか、WITH CHECK OPTION
を伴うビューに影響を及ぼす場合、もしくは外部テーブルがAFTER ROW
トリガを持っていた場合にのみ使われます。
トリガは全列を必要としますが、FDWはRETURNING
句やWITH CHECK OPTION
の制約の内容に応じて返却する列を一部にするか全てにするかを最適化する余地があります。
それとは関係なく、処理成功を表すためになんらかのスロットは返却しなければなりません。さもないと、報告される問い合わせの結果行数が誤った値になってしまいます。
もしExecForeignUpdate
ポインタがNULL
に設定されている場合は、外部テーブルへの更新の試みはエラーメッセージとともに失敗します。
TupleTableSlot * ExecForeignDelete(EState *estate, ResultRelInfo *rinfo, TupleTableSlot *slot, TupleTableSlot *planSlot);
外部テーブルからタプルを一つ削除します。
estate
はその問い合わせのグローバルな実行状態です。
rinfo
は対象の外部テーブルを表すResultRelInfo
構造体です。
slot
にはタプルの新しいデータが含まれます。その行型定義は外部テーブルと一致します。
planSlot
にはModifyTable
プランノードのサブプランが生成したタプルが含まれます。実際、AddForeignUpdateTargets
が要求するジャンク列はこのスロットが運びます。ジャンク列は削除されるタプルを識別するために使用しなければなりません。
戻り値は実際に削除されたデータを含むスロットか、または(一般的にトリガーの結果)実際には削除されなかった場合はNULLです。
渡されたslot
は返却するタプルを保持する用途に利用可能です。
返却されたスロット内のデータはDELETE
問い合わせがRETURNING
句を持っていた場合もしくは外部テーブルがAFTER ROW
トリガを持っていた場合にのみ使われます。
トリガは全列を必要としますが、FDWはRETURNING
句の内容に応じて返却する列を一部にするか全てにするかを最適化する余地があります。
それとは関係なく、処理成功を表すためになんらかのスロットは返却しなければなりません。さもないと、報告される問い合わせの結果行数が誤った値になってしまいます。
もしExecForeignDelete
ポインタがNULL
に設定されている場合は、外部テーブルからの削除の試みはエラーメッセージとともに失敗します。
void EndForeignModify(EState *estate, ResultRelInfo *rinfo);
テーブル更新を終えてリソースを解放します。 通常、pallocされたメモリを解放することは重要ではありませんが、たとえば開いたファイルやリモートサーバへの接続などはクリーンアップするべきです。
もしEndForeignModify
ポインタがNULL
に設定されている場合は、エクゼキュータ終了時には追加処理は何も実行されません。
INSERT
あるいはCOPY FROM
でパーティション化テーブルに挿入されたタプルはパーティションに転送されます。
FDWが外部テーブルのパーティションへの転送をサポートしているなら、以下のコールバック関数も提供すべきです。
これらの関数は、外部テーブルでCOPY FROM
が実行された時に呼び出されます。
void BeginForeignInsert(ModifyTableState *mtstate, ResultRelInfo *rinfo);
外部テーブルへの挿入操作の実行を開始します。
このルーチンは、タプル転送のためにパーティションが選択された場合か、COPY FROM
コマンドでターゲットが指定された場合に、最初の行が外部テーブルに挿入される直前に呼び出されます。
この関数は、実際の挿入に先立つすべての必要な初期化を実行すべきです。
続いて、ExecForeignInsert
またはExecForeignBatchInsert
が外部テーブルにタブルを挿入するために呼び出されます。
mtstate
は、実行中のModifyTable
プランノードの全体的な状態です。
プランのグローバルデータと実行状態がこの構造体を通じて得られます。
rinfo
はResultRelInfo
構造体で、ターゲットの外部テーブルを記述します。
(この操作中に必要なFDWのプライベート状態を保存するためにResultRelInfo
のri_FdwState
フィールドが利用可能です。)
この関数がCOPY FROM
コマンドで呼ばれると、外部テーブルがタプル転送で選択された対象なのか、あるいはコマンドがターゲットを指定したのかに関わらず、mtstate
中のプランに関係するグローバルデータは提供されず、次に個々の挿入されるタプルに対して呼び出されるExecForeignInsert
のplanSlot
パラメータはNULL
となります。
BeginForeignInsert
ポインターがNULL
なら、初期化処理は実施されません。
FDWが外部テーブルパーティションのタプル転送をサポートしていないか、または外部テーブルに対してCOPY FROM
の実行をサポートしていないか、あるいはその両方なら、この関数あるいは以後呼ばれたExecForeignInsert/ExecForeignBatchInsert
は、必ず必要なだけエラーを引き起こします。
void EndForeignInsert(EState *estate, ResultRelInfo *rinfo);
挿入操作を終了してリソースを解放します。 通常、pallocされたメモリを解放することは重要ではありませんが、たとえば開いたファイルやリモートサーバへの接続などはクリーンアップするべきです。
EndForeignInsert
ポインターが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
のビューの表示で更新可否を判定するのに使用されます。)
外部テーブルへの挿入、更新、削除は、代替インタフェース一式を実装することで最適化できます。
通常の挿入、更新、削除のインタフェースは行をリモートサーバから取得し、その後、それらの行を一つずつ変更します。
一部の場合にはこの一行ごとのやり方は必要ですが、非効率とも言えます。
外部サーバについて行が本当はそれらを引き出すことなしに変更されるべきと判断できて、操作に影響を与える仕組み(行レベルのローカルトリガ、格納生成列、あるいは、親ビューからのWITH CHECK OPTION
の制約)が無いならば、操作全体がリモートサーバで実行されるように計画することができます。
以下に示すインタフェースはこれを可能にします。
bool PlanDirectModify(PlannerInfo *root, ModifyTable *plan, Index resultRelation, int subplan_index);
リモートサーバ上で直接変更を実行することが安全かを判断します。
そうであれば、そのために必要なプラン作成の動作を実行した後にtrue
を返します。
さもなくば、false
を返します。
この省略可能な関数は問い合わせのプラン作成時に呼ばれます。
この関数が成功すると、BeginDirectModify
、IterateDirectModify
、EndDirectModify
が実行段階で代わりに呼び出されます。
成功しなければ、テーブルの変更は前述のテーブル更新関数を使って実行されます。
パラメータはPlanForeignModify
に対するものと同じです。
リモートサーバで直接変更を実行するには、本関数は対象サブプランをリモートサーバ上で直接変更するForeignScan
プランノードで書き換えしなければなりません。
ForeignScan
のoperation
とresultRelation
フィールドは適切にセットされる必要があります。
operation
は文の種類に対応するCmdType
列挙値にセットする必要があり(すなわちUPDATE
にはCMD_UPDATE
、INSERT
にはCMD_INSERT
、DELETE
にはCMD_DELETE
)、そして、resultRelation
引数はresultRelation
フィールドにコピーされる必要があります。
追加情報は57.4を参照してください。
PlanDirectModify
ポインタにNULL
が設定されている場合、
リモートサーバでの直接変更の実行は試みられません。
void BeginDirectModify(ForeignScanState *node, int eflags);
リモートサーバでの直接変更を実行する準備をします。
この関数はエクゼキュータが開始するときに呼び出されます。
この関数は(最初のIterateDirectModify
呼び出しで実行されるであろう)直接変更より前に必要とされる全ての初期化を実行するべきです。
ForeignScanState
ノードはすでに作られていますが、fdw_state
がフィールドはまだNULLです。
変更するテーブルに関する情報はForeignScanState
ノードを通して(具体的にはPlanDirectModify
で提供されるFDWプライベート情報を含む、元となるForeignScan
プランノードから)入手可能です。
eflags
は、このプランノードに関するエクゼキュータの操作モードを表すフラグビットを含みます。
(eflags & EXEC_FLAG_EXPLAIN_ONLY)
が真の場合、この関数は外部に見える処理を実行すべきではないことに注意してください。
ExplainDirectModify
やEndDirectModify
用にノード状態を有効にするのに必要な最小限のことだけを実行するべきです。
BeginDirectModify
ポインタがNULL
に設定されている場合、リモートサーバでの直接変更の実行は試みられません。
TupleTableSlot * IterateDirectModify(ForeignScanState *node);
INSERT
、UPDATE
、または、DELETE
の問い合わせがRETURNING
句を持たないときには、リモートサーバでの直接変更の後、単にNULLが返ります。
問い合わせがRETURNING
句を持つときには、RETURNING
計算に必要なデータを含む結果を一つ取り出し、タプルテーブルスロットでそれを返します(この用途にはノードのScanTupleSlot
を使うべきです)。
実際に挿入、更新、削除されたデータはnode->resultRelInfo->ri_projectReturning->pi_exprContext->ecxt_scantuple
に格納されなければなりません。
有効な行がそれ以上なければNULLを返します。
これは呼び出しの間でリセットされる寿命の短いメモリコンテキストで呼び出されることに注意してください。
より長命な格納場所を必要とするなら、BeginDirectModify
でメモリコンテキストを作るか、ノードのEState
のes_query_cxt
を使ってください。
返される行は、ターゲットリストfdw_scan_tlist
が提供されたなら、それとマッチしなければならず、提供されていない場合は変更されている外部テーブルの行型とマッチしなければなりません。
RETURNING
計算に不要な列を取り出さないように最適化することを選ぶなら、それらの列の位置にNULLを入れるか、あるいはそれらの列を除いたfdw_scan_tlist
リストを生成するべきです。
問い合わせが句をもつかどうかによらず、問い合わせが報告する行数はFDW自身によって増加されなければなりません。
問い合わせが句を持たないときも、FDWはEXPLAIN ANALYZE
の場合のForeignScanState
nodeむけに行数を増加させなければなりません。
IterateDirectModify
ポインタがNULL
に設定されている場合、リモートサーバでの直接変更の実行は試みられません。
void EndDirectModify(ForeignScanState *node);
リモートサーバでの直接変更の後、クリーンアップします。 通常、pallocされたメモリを解放することは重要ではありませんが、たとえば開いたファイルやリモートサーバへの接続などはクリーンアップするべきです。
EndDirectModify
ポインタがNULL
に設定されている場合、リモートサーバでの直接変更の実行は試みられません。
TRUNCATE
のためのFDWルーチン
void ExecForeignTruncate(List *rels, DropBehavior behavior, bool restart_seqs);
外部テーブルを切り捨てます。
この関数はTRUNCATEが外部テーブルに対して実行されたときに呼び出されます。
rels
は切り捨てられる外部テーブルのRelation
データ構造のリストです。
behavior
はDROP_RESTRICT
かDROP_CASCADE
のいずれかで、それぞれ元のTRUNCATE
コマンドでRESTRICT
またCASCADE
オプションが要求されたことを表しています。
restart_seqs
がtrue
の場合、元のTRUNCATE
コマンドがRESTART IDENTITY
動作が要求され、それ以外の場合はCONTINUE IDENTITY
動作が要求されていたことになります。
元のTRUNCATE
コマンドで指定されたONLY
オプションはExecForeignTruncate
に渡されないことに注意してください。
この動作は外部テーブルに対するSELECT
とUPDATE
、DELETE
のコールバック関数と同様です。
ExecForeignTruncate
は、外部テーブルが切り捨てられる外部サーバごとに一度呼び出されます。
これは、rels
に含まれるすべての外部テーブルが同じサーバーに所属していなければならないことを意味しています。
ExecForeignTruncate
ポインタがNULL
に設定されている場合、外部テーブルを切り捨てる試みはエラーメッセージとともに失敗します。
FDWが(57.5で説明される)遅延行ロックをサポートする場合は、以下のコールバック関数を提供する必要があります。
RowMarkType GetForeignRowMarkType(RangeTblEntry *rte, LockClauseStrength strength);
行の印付けでどのオプションを外部テーブルに使うかを報告します。
rte
はテーブルのRangeTblEntry
ノードで、strength
は関連するFOR UPDATE/SHARE
句があれば、それが要求するロックの強さを表します。
その結果は、RowMarkType
列挙型のメンバーでなければなりません。
この関数はUPDATE
、DELETE
、SELECT FOR UPDATE/SHARE
の問い合わせに現れ、かつUPDATE
あるいはDELETE
の対象ではない各外部テーブルについて、問い合わせの計画時に呼び出されます。
GetForeignRowMarkType
のポインタがNULL
に設定されていると、必ずROW_MARK_COPY
オプションが使われます。
(これはRefetchForeignRow
が決して呼び出されないので、それを提供する必要もない、ということを意味します。)
さらなる情報については57.5を参照してください。
void RefetchForeignRow(EState *estate, ExecRowMark *erm, Datum rowid, TupleTableSlot *slot, bool *updated);
必要ならロックした後で、外部テーブルから1つのタプルスロットを再フェッチします。
estate
は問い合わせのグローバルな実行状態です。
erm
は対象の外部テーブルおよび獲得する行ロックの種別(あれば)を記述するExecRowMark
構造体です。
rowid
はフェッチするタプルを特定するものです。
slot
は呼び出しで役立つ内容は含みませんが、返されたタプルを保持するために使用できます。
updated
は出力パラメータです。
この関数はタプルを与えられたスロットに格納するか、あるいは行ロックが取得できなければタプルをクリアします。
獲得する行ロックの種別はerm->markType
で指定されます。この値は事前にGetForeignRowMarkType
から返されたものです。
(ROW_MARK_REFERENCE
は行のロックを獲得せずに、単にタプルを再フェッチすることを意味し、また、ROW_MARK_COPY
はこのルーチンで使われることはありません。)
そして、*updated
はフェッチしたタプルが、以前に取得したものと同じではなく、更新されたバージョンであったときにtrue
にセットされます。
(どちらなのかFDWが判断できない場合は、true
を返すことが推奨されます)。
デフォルトでは、行ロックの獲得に失敗したときはエラーを発生させるべきであることに注意してください。
空スロットを返すのが適切なのは、erm->waitPolicy
でSKIP LOCKED
オプションが指定されている場合だけです。
rowid
は、再フェッチする行を以前読んだ時のctid
値です。
rowid
値はDatum
として渡されますが、現在はtid
にしかなりません。
将来は行ID以外のデータ型が可能になることを期待して、関数APIとすることが選択されました。
RefetchForeignRow
ポインタがNULL
の場合、行を再フェッチする試みは失敗し、エラーメッセージを発行します。
さらなる情報については57.5を参照してください。
bool RecheckForeignScan(ForeignScanState *node, TupleTableSlot *slot);
以前に戻されたタプルが、関連するスキャンおよび結合の制約とまだ一致しているか再検査し、更新されたバージョンのタプルを提供する場合もあります。
結合のプッシュダウンを行わない外部データラッパでは、通常は、これをNULL
にセットし、代わりにfdw_recheck_quals
を適切にセットする方が便利でしょう。
しかし、外部結合をプッシュダウンする場合、すべてのベーステーブルに関する検査を結果のタプルに適用するだけでは、たとえすべての必要な属性がそこにあったとしても十分ではありません。
なぜなら一部の制約が一致しないことで、タプルが戻されない代わりに、一部の属性がNULLになってしまうかもしれないからです。
RecheckForeignScan
制約を再検査し、それが依然として満たされていれば真を、そうでなければ偽を返すことができます。
それだけでなく、置換されたタプルを提供されたスロットに格納することもできます。
結合のプッシュダウンを実装する場合、外部データラッパは通常、再検査のためだけに使用される代替のローカル結合プランを構築します。
これがForeignScan
の外部サブプランとなります。
再検査が必要な時は、このサブプランを実行して、結果のタプルをスロットに格納することができます。
どのベーステーブルも最大で1行しか返さないので、このプランは効率的である必要はありません。
例えば、すべての結合をネステッドループで実装することもできます。
関数GetExistingLocalJoinPath
は、存在するパスから代替ローカルの結合プランとして使用可能な適当なローカル結合パスを検索するのに使われるかもしれません。
GetExistingLocalJoinPath
は指定された結合リレーションのパスリストのパラメータ化されていないパスを検索します。
(そのようなパスが見つからなかった場合はNULLを返します。この場合、外部データラッパはそれ自身によりローカルパスを構築するかもしれず、あるいは、その結合むけのアクセスパスを作らないことを選択するかもしれません。)
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
の場合には、実行時統計情報を提供するためにModifyTableState
ノードの状態を調べることができます。
最初の4つの引数はBeginForeignModify
と同じです。
もしExplainForeignModify
ポインタがNULL
に設定されている場合は、EXPLAIN
中に追加情報は表示されません。
void ExplainDirectModify(ForeignScanState *node, ExplainState *es);
リモートサーバでの直接変更について追加EXPLAIN
出力を表示します。
この関数はEXPLAIN
出力にフィールドを加えるためにExplainPropertyText
と関連の関数を呼ぶことができます。
es
の中のフラグフィールドは何を表示するかを決めるのに使用できます。また、EXPLAIN ANALYZE
の場合には、実行時統計情報を提供するためにForeignScanState
ノードの状態を調べることができます。
ExplainDirectModify
ポインタがNULL
に設定されている場合は、EXPLAIN
中に追加情報は表示されません。
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に設定してください。)
IMPORT FOREIGN SCHEMA
のためのFDWルーチン
List * ImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid);
外部テーブル作成コマンドのリストを取得します。 この関数はIMPORT FOREIGN SCHEMAを実行する時に呼び出され、その文の解析木と外部サーバが使用するOIDとを渡されます。 C文字列のリストを返し、その各文字列はCREATE FOREIGN TABLEコマンドを含んでいる必要があります。 これらの文字列はコアサーバが解析して実行します。
ImportForeignSchemaStmt
構造体において、remote_schema
はリモートスキーマの名前で、そこからテーブルがインポートされます。
list_type
はテーブル名のフィルタ方法を指定します。
ここで、FDW_IMPORT_SCHEMA_ALL
はリモートスキーマのすべてのテーブルをインポートすること(この場合、table_list
は空にします)、
FDW_IMPORT_SCHEMA_LIMIT_TO
はtable_list
に列挙されたテーブルだけを含めること、
そしてFDW_IMPORT_SCHEMA_EXCEPT
はtable_list
に列挙されたテーブルを除外することを意味します。
options
はインポートのプロセスで使用されるオプションのリストです。
オプションの意味はFDWに依存します。
例えば、FDWは列のNOT NULL
属性をインポートするかどうかを定めるオプションを使うことができます。
これらのオプションはFDWがデータベースオブジェクトのオプションとしてサポートするものと何ら関係ある必要はありません。
FDWはImportForeignSchemaStmt
のlocal_schema
フィールドを無視しても良いです。
なぜなら、コアサーバは解析されたCREATE FOREIGN TABLE
コマンドにその名前を自動的に挿入するからです。
FDWはlist_type
およびtable_list
で指定されるフィルタの実装にも注意する必要はありません。
なぜなら、コアサーバはそれらのオプションによって除外されるテーブルに対して戻されたコマンドをすべて自動的にスキップするからです。
しかし、除外されるテーブルについてコマンドを作成する作業を回避するのは、そもそも役立つことが多いです。
関数IsImportableForeignTable()
は指定の外部テーブル名がフィルタを通るかどうかの検査に役立つかもしれません。
FDWがテーブル定義のインポートをサポートしない場合は、ImportForeignSchema
ポインタをNULL
にセットすることができます。
ForeignScan
ノードは、オプションとして、パラレル実行をサポートします。
並列ForeignScan
は複数プロセスで実行され、全ての協調プロセスにわたって各行が一度だけ返るようにしなければなりません。
これを行うため、プロセスは動的共有メモリの固定サイズチャンクを通して調整をはかることができます。
この共有メモリは全プロセスで同じアドレスに割り当てされることが保証されませんので、ポインタを含まないようにしなければなりません。
以下のコールバックは一般に全て省略可能ですが、パラレル実行をサポートするためには必要です。
bool IsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte);
スキャンがパラレルワーカーで実行できるかテストします。 この関数はプランナが並列プランが可能であろうと考えるときだけ呼ばれます。また、そのスキャンにとってパラレルワーカーで実行するのが安全であるとき真を返すべきです。 リモートデータソースがトランザクションのセマンティクスを持つ場合は、一般にあてはまりません。ただし、ワーカーのデータへの接続を何らかの形でリーダーとして同じトランザクション文脈を共有させることができる場合を除きます。
この関数が定義されていない場合、スキャンはパラレルリーダー内で実行しなければならないと想定されます。 真を返すことは、スキャンがパラレルワーカーで実行可能であるだけで、パラレルに実行可能であることを意味するのでは無いことに注意してください。 そのため、この関数を定義することはパラレル実行がサポートされていないときでも役立つ可能性があります。
Size EstimateDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt);
並列操作に必要とされるであろう動的共有メモリ量を推定します。 これは実際に使われる量よりも大きくてよいですが、小さくてはいけません。 戻り値はバイト単位です。 この関数はオプションであり、必要でない場合は省略することができます。 しかし省略された場合、FDWの使用のために共有メモリが割り当てられないため、次の3つの関数も省略しなければなりません。
void InitializeDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt, void *coordinate);
並列処理で必要とされる動的共有メモリを初期化します。
coordinate
はEstimateDSMForeignScan
の戻り値に等しいサイズの共有メモリ領域へのポインタです。
この関数はオプションであり、必要でない場合は省略することができます。
void ReInitializeDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt, void *coordinate);
外部スキャンプランノードが再スキャンされようとしているときに、並列操作に必要な動的共有メモリーを再初期化します。
この関数はオプションであり、必要でない場合は省略することができます。
ReScanForeignScan
関数はローカル状態のみをリセットし、この関数は共有状態のみをリセットすることをお勧めします。
現在、この関数はReScanForeignScan
より前に呼び出されますが、その順序に依存しないようにする方が良いでしょう。
void InitializeWorkerForeignScan(ForeignScanState *node, shm_toc *toc, void *coordinate);
InitializeDSMForeignScan
でリーダーがセットアップした共有状態に基づくパラレルワーカーのローカル状態を初期化します。
この関数はオプションであり、必要でない場合は省略することができます。
void ShutdownForeignScan(ForeignScanState *node);
ノードが完了するまで実行されないことが予想されるときにリソースを解放します。
これはすべてのケースで呼ばれるわけではありません。
EndForeignScan
は、この関数が最初に呼び出されなくても呼び出されることがあります。
このコールバックが呼び出された直後に、パラレルクエリで使用されるDSM(動的共有メモリ)セグメントが破棄されるため、DSMセグメントがなくなる前に何らかのアクションを実行する外部データラッパーがこのメソッドを実装する必要があります。
ForeignScan
ノードは、オプションとしてsrc/backend/executor/README
に記述されているように、非同期実行をサポートすることが可能です。
以下の関数はすべてオプションですが、非同期実行をサポートする場合はすべて必須です。
bool IsForeignPathAsyncCapable(ForeignPath *path);
与えられたForeignPath
パスが、そもそも外部リレーションを非同期でスキャンできるかどうかをテストします。
この関数は与えられたパスがAppendPath
パスの直接の子であり、プランナが非同期実行が性能を向上させると考える場合にのみ、問い合わせ計画の最後で呼ばれ、与えられたパスが外部リレーションを非同期にスキャンできる場合に真を返さなければなりません。
この関数が定義されていない場合、与えられたパスはIterateForeignScan
を使用して外部リレーションをスキャンすることが想定されます。
(これは以下で説明されるコールバック関数が決して呼ばれないことを意味します。呼ばれないことを意味するので、それらも提供される必要はありません。)
void ForeignAsyncRequest(AsyncRequest *areq);
ForeignScan
ノードから非同期に1つのタプルを生成します。
areq
はForeignScan
ノードと、そこからタプルを要求した親Append
ノードを記述するAsyncRequest
構造体です。
areq->result
で指定されたスロットにタプルを格納し、areq->request_complete
にtrue
を設定します。
または、ネットワークI/Oなどコアサーバの外部のイベントを待つ必要があり、すぐにタプルを生成できない場合は、フラグをfalse
に、areq->callback_pending
をtrue
に設定して、ForeignScan
ノードが後述のコールバック関数からコールバックを取得するようにします。
それ以上のタプルがない場合、スロットにNULLまたは空のスロットを設定し、areq->request_complete
フラグにtrue
を設定します。
ExecAsyncRequestDone
やExecAsyncRequestPending
を使ってareq
に出力パラメータを設定することが推奨されています。
void ForeignAsyncConfigureWait(AsyncRequest *areq);
ForeignScan
ノードが待機したいファイル記述子イベントを設定します。
この関数は、ForeignScan
ノードにareq->callback_pending
フラグが設定されている場合にのみ呼び出され、areq
で記述された親ノードAppend
のas_eventset
にイベントを追加しなければなりません。
詳細はsrc/backend/executor/execAsync.c
のExecAsyncConfigureWait
に対するコメントを参照してください。
ファイルディスクリプタのイベントが発生すると、ForeignAsyncNotify
が呼ばれます。
void ForeignAsyncNotify(AsyncRequest *areq);
発生した関連イベントを処理し、ForeignScan
ノードから非同期に1つのタプルを生成します。
この関数はForeignAsyncRequest
と同じようにareq
に出力パラメータを設定する必要があります。
List * ReparameterizeForeignPathByChild(PlannerInfo *root, List *fdw_private, RelOptInfo *child_rel);
この関数は、child_rel
で指定された子リレーションの最上位の親によってパラメータ化されたパスを、子リレーションによってパラメータ化されたパスに変換する際に呼び出されます。
この関数はパスをパラメータ化する、あるいはForeignPath
のfdw_private
メンバーに保存されている式ノードを変換するために使用されます。
このコールバックは必要に応じて、reparameterize_path_by_child
、adjust_appendrel_attrs
あるいはadjust_appendrel_attrs_multilevel
を呼び出すことができます。