PostgreSQL 外部數(shù)據(jù)包裝器回調(diào)例程

2021-09-15 10:40 更新
56.2.1. 用于掃描外部表的FDW例程
56.2.2. 用于掃描外部連接的 FDW 例程
56.2.3. 用于規(guī)劃掃描/連接后處理的 FDW 例程
56.2.4. 更新外部表的FDW例程
56.2.5. 用于行鎖定的 FDW 例程
56.2.6. EXPLAIN的FDW例程
56.2.7. ANALYZE的FDW例程
56.2.8. IMPORT FOREIGN SCHEMA的 FDW 例程
56.2.9. 并行執(zhí)行的 FDW 例程
56.2.10. 用于路徑重新參數(shù)化的FDW例程

FDW處理器函數(shù)返回一個(gè)palloc過的FdwRoutine結(jié)構(gòu),它包含下文描述的回調(diào)函數(shù)的指針。掃描相關(guān)的函數(shù)是必需的,剩下的是可選的。

FdwRoutine結(jié)構(gòu)類型被聲明在src/include/foreign/fdwapi.h中,可以查看它來獲得額外的信息。

56.2.1. 用于掃描外部表的FDW例程

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

獲取一個(gè)外部表的關(guān)系尺寸估計(jì)。在對(duì)一個(gè)掃描外部表的查詢進(jìn)行規(guī)劃的開頭將調(diào)用該函數(shù)。root是規(guī)劃器的關(guān)于該查詢的全局信息;baserel是規(guī)劃器的關(guān)于該表的信息;foreigntableid是外部表在pg_class中的 OID (foreigntableid可以從規(guī)劃器的數(shù)據(jù)結(jié)構(gòu)中獲得,但是為了減少工作量,這里直接顯式地將它傳遞給函數(shù))。

這個(gè)函數(shù)應(yīng)該更新baserel->rows為表掃描根據(jù)限制條件完成了過濾后將返回的預(yù)期行數(shù)。 baserel->rows的初始值只是一個(gè)常數(shù)的默認(rèn)估計(jì)值,應(yīng)該盡可能把它替換掉。 如果該函數(shù)能夠計(jì)算出一個(gè)平均結(jié)果行寬度的更好的估計(jì)值,該函數(shù)也可能選擇更新baserel->width。 (初始值基于列數(shù)據(jù)類型和最后一個(gè) ANALYZE測(cè)量的列平均寬度值。) 此外,如果該函數(shù)能夠更好地計(jì)算出外部表的總行數(shù),則該函數(shù)可以更新baserel->tuples。 (初始值來自pg_class。reltuples表示最后一次ANALYZE看到的總行數(shù)。)

更多信息請(qǐng)見第 56.4 節(jié)

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

為一個(gè)外部表上的掃描創(chuàng)建可能的訪問路徑。這個(gè)函數(shù)在查詢規(guī)劃過程中被調(diào)用。參數(shù)和GetForeignRelSize相同,后者已經(jīng)被調(diào)用過了。

這個(gè)函數(shù)必須為外部表上的掃描生成至少一個(gè)訪問路徑(ForeignPath節(jié)點(diǎn)),并且必須調(diào)用add_path把每一個(gè)這樣的路徑加入到baserel->pathlist中。我們推薦使用create_foreignscan_path來建立ForeignPath節(jié)點(diǎn)。該函數(shù)可以生成多個(gè)訪問路徑,例如一個(gè)具有合法 pathkeys的路徑表示一個(gè)預(yù)排序好的結(jié)果。每一個(gè)反問路徑必須包含代價(jià)估計(jì),并且能包含任何FDW的私有信息,這種信息被用來標(biāo)識(shí)想要使用的指定掃描方法。

更多信息請(qǐng)見第 56.4 節(jié)。

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

從選擇的外部訪問路徑創(chuàng)建一個(gè)ForeignScan計(jì)劃節(jié)點(diǎn)。這個(gè)函數(shù)在查詢規(guī)劃的末尾被調(diào)用。參數(shù)和GetForeignRelSize的一樣,外加選中的ForeignPath(在前面由GetForeignPaths、GetForeignJoinPaths或者 GetForeignUpperPaths產(chǎn)生)、被計(jì)劃節(jié)點(diǎn)發(fā)出的目標(biāo)列表以及計(jì)劃節(jié)點(diǎn)強(qiáng)制的限制子句以及被RecheckForeignScan執(zhí)行的復(fù)查所使用的ForeignScan的外子計(jì)劃(如果該路徑是用于一個(gè)連接而非基本關(guān)系,則foreigntableidInvalidOid)。

這個(gè)函數(shù)必須創(chuàng)建并返回一個(gè)ForeignScan計(jì)劃節(jié)點(diǎn),我們對(duì)劍使用make_foreignscan來建立ForeignScan節(jié)點(diǎn)。

更多信息見第 56.4 節(jié)。

void
BeginForeignScan(ForeignScanState *node,
                 int eflags);

開始執(zhí)行一個(gè)外部掃描。這個(gè)函數(shù)在執(zhí)行器啟動(dòng)階段被調(diào)用。它應(yīng)該執(zhí)行任何在掃描能夠開始之前需要完成的初始化工作,但是并不開始執(zhí)行真正的掃描(會(huì)在第一次調(diào)用IterateForeignScan時(shí)完成)。ForeignScanState節(jié)點(diǎn)已經(jīng)被創(chuàng)建好了,但是它的fdw_state域仍然為 NULL。關(guān)于要被掃描的表的信息可以通過 ForeignScanState節(jié)點(diǎn)訪問(特殊地,從底層的ForeignScan計(jì)劃節(jié)點(diǎn),它包含任何由GetForeignPlan提供的FDW私有信息)。eflags包含描述執(zhí)行器對(duì)該計(jì)劃節(jié)點(diǎn)操作模式的標(biāo)志位。

注意當(dāng)(eflags & EXEC_FLAG_EXPLAIN_ONLY)為真時(shí),這個(gè)函數(shù)不應(yīng)該執(zhí)行任何外部可見的動(dòng)作;它應(yīng)當(dāng)只做最少的事情來創(chuàng)建對(duì)ExplainForeignScanEndForeignScan有效的節(jié)點(diǎn)狀態(tài)。

TupleTableSlot *
IterateForeignScan(ForeignScanState *node);

從外部源獲得一行,將它放在一個(gè)元組表槽中返回(節(jié)點(diǎn)的ScanTupleSlot應(yīng)當(dāng)被用于此目的)。如果沒有更多的行可用則返回 NULL。元組表槽設(shè)施允許一個(gè)物理的或者虛擬的元組被返回;在大部分情況下出于性能的考慮會(huì)傾向于選擇后者。注意這是在一個(gè)短期存在的內(nèi)存上下文中被調(diào)用的,該內(nèi)存上下文會(huì)在調(diào)用之間被重置。如果你需要長(zhǎng)期存在的存儲(chǔ),請(qǐng)?jiān)?code class="function">BeginForeignScan中創(chuàng)建內(nèi)存上下文,或者使用節(jié)點(diǎn)的 EState中的es_query_cxt

如果提供了fdw_scan_tlist目標(biāo)列表,被返回的行必須匹配它,如果沒有提供則它們必須匹配被掃描的外部表的行類型。如果選擇優(yōu)化掉不需要的列,你應(yīng)該在那些列的位置上插入控制或者生成一個(gè)忽略了那些列的fdw_scan_tlist列表。

注意PostgreSQL的執(zhí)行器并不在乎被返回的行是否違背了定義在該外部表上的任何約束 — 但是規(guī)劃器會(huì)在乎這一點(diǎn),并且如果在外部表中有可見行不滿足一個(gè)約束,規(guī)劃器可能會(huì)錯(cuò)誤地優(yōu)化查詢。如果當(dāng)用戶已經(jīng)聲明一個(gè)約束應(yīng)該為真時(shí)它卻被違背,最合適的處理可能是產(chǎn)生一個(gè)錯(cuò)誤(就像在數(shù)據(jù)類型失配的情況下所作的那樣)。

void
ReScanForeignScan(ForeignScanState *node);

從頭開始重啟一個(gè)掃描。注意掃描所依賴的任何參數(shù)可能已經(jīng)改變了值,因此新掃描不一定會(huì)返回完全相同的行。

void
EndForeignScan(ForeignScanState *node);

結(jié)束掃描并釋放資源。通常釋放palloc過的內(nèi)存并不重要,但是打開的文件和到遠(yuǎn)程服務(wù)器的連接等應(yīng)該被清理。

56.2.2. 用于掃描外部連接的 FDW 例程

如果一個(gè) FDW 支持遠(yuǎn)程執(zhí)行外部連接(而不是先把兩個(gè)表的數(shù)據(jù)取到本地然后做本地連接),它應(yīng)該提供這個(gè)回調(diào)函數(shù):

void
GetForeignJoinPaths(PlannerInfo *root,
                    RelOptInfo *joinrel,
                    RelOptInfo *outerrel,
                    RelOptInfo *innerrel,
                    JoinType jointype,
                    JoinPathExtraData *extra);

它為兩個(gè)(或更多)同屬于一臺(tái)外部服務(wù)器的外部表的連接創(chuàng)建可能的訪問路徑。這個(gè)可選的函數(shù)會(huì)在查詢規(guī)劃過程中被調(diào)用。 和GetForeignPaths一樣,這個(gè)函數(shù)應(yīng)該為提供的joinrel生成ForeignPath路徑(用 create_foreign_join_path 構(gòu)建它們),并且調(diào)用 add_path把這些路徑加入到該連接應(yīng)該考慮的路徑集合中。但是和GetForeignPaths不一樣的是,不需要這個(gè)函數(shù)產(chǎn)生最少一個(gè)路徑,因?yàn)樯婕氨镜剡B接的路徑總是可用的。

注意為相同的連接關(guān)系將會(huì)重復(fù)地調(diào)用這個(gè)函數(shù)用來生成內(nèi)外關(guān)系的不同組合。FDW 需要負(fù)責(zé)最小化其中重復(fù)的工作。

如果一個(gè)ForeignPath路徑被選中用于該連接,它將在整個(gè)連接處理中存在,為其中的成分表和子連接產(chǎn)生的路徑將不會(huì)被使用。后續(xù)對(duì)該連接路徑的處理大部分和掃描單個(gè)外部表的路徑一樣。一點(diǎn)不同是ForeignScan計(jì)劃節(jié)點(diǎn)的scanrelid應(yīng)該被設(shè)置為零,因?yàn)樗硎镜牟皇菃蝹€(gè)關(guān)系,而是用ForeignScan節(jié)點(diǎn)的 fs_relids域來表示被連接的關(guān)系集合(后一個(gè)域會(huì)被核心規(guī)劃器代碼自動(dòng)設(shè)置,不需要由 FDW 填充)。另一點(diǎn)不同是,由于一個(gè)遠(yuǎn)程連接的列列表無法在系統(tǒng)目錄中找到,F(xiàn)DW 必須用一個(gè)合適的TargetEntry節(jié)點(diǎn)列表來填充fdw_scan_tlist,表示運(yùn)行時(shí)它返回的元組中提供的列的集合。

更多信息請(qǐng)見第 56.4 節(jié)

56.2.3. 用于規(guī)劃掃描/連接后處理的 FDW 例程

如果一個(gè) FDW 支持執(zhí)行遠(yuǎn)程的掃描/連接后處理,例如遠(yuǎn)程聚集,那么它應(yīng)該提供這個(gè)回調(diào)函數(shù):

void
GetForeignUpperPaths(PlannerInfo *root,
                     UpperRelationKind stage,
                     RelOptInfo *input_rel,
                     RelOptInfo *output_rel,
                     void *extra);

上層關(guān)系處理創(chuàng)建可能的訪問路徑,這是規(guī)劃器針對(duì)所有掃描/連接后查詢處理的術(shù)語,例如聚集、窗口函數(shù)、排序和表更新。在查詢規(guī)劃期間會(huì)調(diào)用這個(gè)可選的函數(shù)。當(dāng)前,只有當(dāng)該查詢中涉及的所有基本關(guān)系都屬于同一個(gè) FDW 時(shí)才會(huì)調(diào)用這個(gè)函數(shù)。 這個(gè)函數(shù)應(yīng)該為 FDW 知道如何遠(yuǎn)程執(zhí)行的任何掃描/連接后處理生成ForeignPath路徑(用 create_foreign_upper_path 構(gòu)建它們),并且調(diào)用 add_path把這些路徑加入到上層關(guān)系中。就GetForeignJoinPaths來說,并不要求這個(gè)函數(shù)在創(chuàng)建任何路徑時(shí)都能成功,因?yàn)槁窂娇偸怯锌赡苌婕暗奖镜靥幚怼?/p>

stage參數(shù)表示當(dāng)前正在考慮的是哪一個(gè)掃描/連接后處理步驟。output_rel是接收表示這一個(gè)步驟的路徑的上層關(guān)系,而input_rel是表示這個(gè)步驟輸入的關(guān)系。 extra參數(shù)提供額外的細(xì)節(jié),當(dāng)前只會(huì)為UPPERREL_PARTIAL_GROUP_AGG或者 UPPERREL_GROUP_AGG設(shè)置它,這種情況下它會(huì)指向一個(gè)GroupPathExtraData結(jié)構(gòu);或者對(duì)于 UPPERREL_FINAL, 在某種情況下它指向一個(gè)FinalPathExtraData 結(jié)構(gòu)。(注意被加入到output_rel中的 ForeignPath路徑通常對(duì)input_rel的路徑?jīng)]有直接的依賴,因?yàn)樗鼈兊奶幚肀徽J(rèn)為是在外部處理的。不過,檢查為前一個(gè)處理步驟生成的路徑有助于避免冗余的規(guī)劃工作)。

更多信息請(qǐng)見第 56.4 節(jié)。

56.2.4. 更新外部表的FDW例程

如果一個(gè)FDW支持可寫的外部表,根據(jù)FDW的需要和功能它應(yīng)該提供某些或者全部下列回調(diào)函數(shù):

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

UPDATEDELETE操作是在之前由表掃描函數(shù)取出的行上被執(zhí)行的。FDW可能需要額外的信息(例如一個(gè)行ID或主鍵列的值)來保證它能夠找到要更新或刪除的準(zhǔn)確行。要支持這些要求,這個(gè)函數(shù)可以項(xiàng)列列表中增加額外的隱藏或junk的目標(biāo)列,它們?cè)谝粋€(gè)UPDATEDELETE期間會(huì)被從外部表中獲取。

要做到這一點(diǎn),向parsetree->targetList中增加TargetEntry項(xiàng),它們包含要被獲取的額外值的表達(dá)式。每一個(gè)這樣的項(xiàng)必須被標(biāo)記為resjunk = true,并且必須有一個(gè)可區(qū)分的resname用于在執(zhí)行期間標(biāo)識(shí)它。請(qǐng)避免使用匹配 ctidN 、wholerowwholerowN 的名字,因?yàn)楹诵南到y(tǒng)可能會(huì)生成使用這些名字的junk列。如果額外的表達(dá)式比簡(jiǎn)單的Var更加復(fù)雜,在把它們加入到目標(biāo)列表之前必須把它們用eval_const_expressions進(jìn)行處理。

盡管這個(gè)函數(shù)在規(guī)劃過程中被調(diào)用,但所提供的信息與其他規(guī)劃例程可用的信息有點(diǎn)區(qū)別。parsetreeUPDATEDELETE命令的分析樹,而target_rtetarget_relation描述目標(biāo)外部表。

如果AddForeignUpdateTargets指針被設(shè)置為NULL,則不會(huì)有額外的目標(biāo)表達(dá)式被加入(這將使得我們不可能實(shí)現(xiàn)DELETE操作,而UPDATE則還有可能是可行的,前提是FDW依賴一個(gè)未改變的主鍵來標(biāo)識(shí)行)。

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

執(zhí)行外部表上插入、更新或刪除所需的任何附加規(guī)劃動(dòng)作。這個(gè)函數(shù)生成FDW私有信息,該信息將被附加到執(zhí)行該更新動(dòng)作的ModifyTable計(jì)劃節(jié)點(diǎn)。這個(gè)私有信息的形式必須是一個(gè)List,并將會(huì)在執(zhí)行階段被傳遞給BeginForeignModify

root是規(guī)劃器關(guān)于該查詢的全局信息。planModifyTable計(jì)劃節(jié)點(diǎn),它除了fdwPrivLists域之外是完整的。resultRelation通過目標(biāo)外部表的范圍表索引來標(biāo)識(shí)它。 subplan_index標(biāo)識(shí)這是ModifyTable計(jì)劃節(jié)點(diǎn)的哪個(gè)目標(biāo),從零開始計(jì)數(shù);如果你希望索引到plan->plans或其他plan節(jié)點(diǎn)的子結(jié)構(gòu)中,請(qǐng)使用它。

更多信息見第 56.4 節(jié)。

如果PlanForeignModify指針被設(shè)置為NULL,則不會(huì)有額外的計(jì)劃時(shí)動(dòng)作被執(zhí)行,并且傳遞給BeginForeignModifyfdw_private列表也將為 NIL。

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

開始執(zhí)行一個(gè)外部表修改操作。這個(gè)例程在執(zhí)行器啟動(dòng)期間被調(diào)用。它應(yīng)該執(zhí)行任何先于實(shí)際表修改的初始化工作。隨后,ExecForeignInsert、ExecForeignUpdateExecForeignDelete將被為每一個(gè)將被插入、更新或刪除的元組調(diào)用。

mtstate是要被執(zhí)行的ModifyTable計(jì)劃節(jié)點(diǎn)的狀態(tài)信息;通過這個(gè)結(jié)構(gòu)可以得到關(guān)于規(guī)劃和執(zhí)行階段的全局?jǐn)?shù)據(jù)。rinfo是描述目標(biāo)外部表的ResultRelInfo結(jié)構(gòu)(ResultRelInfori_FdwState域用于FDW來存儲(chǔ)它在此操作中需要的任何私有狀態(tài))。fdw_private包含PlanForeignModify生成的私有數(shù)據(jù)。subplan_index標(biāo)識(shí)這是ModifyTable計(jì)劃節(jié)點(diǎn)的哪個(gè)目標(biāo)。eflags包含描述執(zhí)行器對(duì)該計(jì)劃節(jié)點(diǎn)操作模式的標(biāo)志位。

注意當(dāng)(eflags & EXEC_FLAG_EXPLAIN_ONLY)為真,這個(gè)函數(shù)不應(yīng)執(zhí)行任何外部可見的動(dòng)作;它只應(yīng)該做最少的工作來創(chuàng)建ExplainForeignModifyEndForeignModify可用的節(jié)點(diǎn)狀態(tài)。

如果BeginForeignModify指針被設(shè)置為NULL,在執(zhí)行器啟動(dòng)期間將不會(huì)采取任何動(dòng)作。

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

插入一個(gè)元組到外部表。estate是查詢的全局執(zhí)行狀態(tài)。rinfo是描述目標(biāo)外部表的ResultRelInfo結(jié)構(gòu)。slot包含要被插入的元組;它將匹配外部表的行類型定義。planSlot包含由 ModifyTable計(jì)劃節(jié)點(diǎn)的子計(jì)劃生成的元組;它與slot不同,它可能包含額外的junk列(INSERT情況通常不關(guān)心planSlot,但是為了完整性還是在這里提供它)。

返回值可以是一個(gè)包含實(shí)際被插入的數(shù)據(jù)的槽(這可能會(huì)和所提供的數(shù)據(jù)不同,例如一個(gè)觸發(fā)器動(dòng)作的結(jié)果),或者為 NULL 表示實(shí)際沒有插入行(還是觸發(fā)器的結(jié)果)。被傳入的slot可以被重用于這個(gè)目的。

在返回槽中的數(shù)據(jù)只有在INSERT語句具有一個(gè)RETURNING子句或包括一個(gè)視圖WITH CHECK OPTION; 或者如果外部表具有一個(gè)AFTER ROW觸發(fā)器時(shí)才被使用。 觸發(fā)器要求所有的列,但是 FDW 應(yīng)該選擇優(yōu)化成根據(jù)RETURNING子句的內(nèi)容或 WITH CHECK OPTION約束返回某些或全部列。 不管怎樣,某些槽必須被返回來指示成功,或者查詢報(bào)告的行計(jì)數(shù)將會(huì)是錯(cuò)誤的。

如果ExecForeignInsert指針被設(shè)置為NULL,嘗試向外部表插入將會(huì)失敗并報(bào)告一個(gè)錯(cuò)誤消息。

請(qǐng)注意,在外表上將路由元組插入外表分區(qū)或執(zhí)行 COPY FROM 時(shí)也會(huì)調(diào)用此函數(shù),在這種情況下,它的調(diào)用方式與INSERT 中的情況有所不同。 請(qǐng)參閱下面所述的允許 FDW 支持的回調(diào)函數(shù)。

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

更新外部表中的一個(gè)元組。estate是查詢的全局執(zhí)行狀態(tài)。rinfo是描述目標(biāo)外部表的ResultRelInfo結(jié)構(gòu)。slot包含元組的新數(shù)據(jù);它將匹配外部表的行類型定義。planSlot包含由 ModifyTable計(jì)劃節(jié)點(diǎn)的子計(jì)劃生成的元組;它與slot不同,它可能包含額外的junk列(INSERT情況通常不關(guān)心planSlot,但是為了完整性還是在這里提供它)。特殊地,任何AddForeignUpdateTargets所要求的junk列在這個(gè)槽中都是有效的。

返回值可以是一個(gè)包含實(shí)際被更新的數(shù)據(jù)的槽(這可能會(huì)和所提供的數(shù)據(jù)不同,例如一個(gè)觸發(fā)器動(dòng)作的結(jié)果),或者為 NULL 表示實(shí)際沒有更新行(還是觸發(fā)器的結(jié)果)。被傳入的slot可以被重用于這個(gè)目的。

在返回槽中的數(shù)據(jù)只有在UPDATE語句具有一個(gè)RETURNING子句或者包括一個(gè)視圖WITH CHECK OPTION;或者如果外部表具有一個(gè)AFTER ROW觸發(fā)器時(shí)才被使用。 觸發(fā)器要求所有的列,但是 FDW 應(yīng)該選擇優(yōu)化成根據(jù)RETURNING子句的內(nèi)容或 WITH CHECK OPTION約束返回某些或全部列。 不管怎樣,某些槽必須被返回來指示成功,或者查詢報(bào)告的行計(jì)數(shù)將會(huì)是錯(cuò)誤的。

如果ExecForeignUpdate指針被設(shè)置為NULL,嘗試更新外部表將會(huì)失敗并報(bào)告一個(gè)錯(cuò)誤消息。

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

從外部表刪除一個(gè)元組。estate是查詢的全局執(zhí)行狀態(tài)。rinfo是描述目標(biāo)外部表的ResultRelInfo結(jié)構(gòu)。slot在調(diào)用時(shí)不包含任何有用的東西,但是可以被用于保持被返回的元組。planSlot包含由 ModifyTable計(jì)劃節(jié)點(diǎn)的子計(jì)劃生成的元組;特殊地,它將攜帶AddForeignUpdateTargets所要求的任意垃圾列。垃圾列被用來標(biāo)識(shí)要被刪除的元組。

返回值可以是一個(gè)包含實(shí)際被刪除的數(shù)據(jù)的槽(這可能會(huì)和所提供的數(shù)據(jù)不同,例如一個(gè)觸發(fā)器動(dòng)作的結(jié)果),或者為 NULL 表示實(shí)際沒有刪除行(還是觸發(fā)器的結(jié)果)。被傳入的slot可以被重用于這個(gè)目的。

在返回槽中的數(shù)據(jù)只有在DELETE查詢具有一個(gè)RETURNING子句或者外部表具有一個(gè)AFTER ROW觸發(fā)器時(shí)才被使用。觸發(fā)器要求所有的列,但是 FDW 應(yīng)該選擇優(yōu)化成根據(jù)RETURNING子句的內(nèi)容返回某些或全部列。不管怎樣,某些槽必須被返回來指示成功,或者查詢報(bào)告的行計(jì)數(shù)將會(huì)是錯(cuò)誤的。

如果ExecForeignDelete指針被設(shè)置為NULL,嘗試從外部表中刪除將會(huì)失敗并報(bào)告一個(gè)錯(cuò)誤消息。

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

結(jié)束表更新并釋放資源。通常釋放palloc的內(nèi)存并不重要,但是打開的文件和到遠(yuǎn)程服務(wù)器的連接等應(yīng)當(dāng)被清除。

如果EndForeignModify指針被設(shè)置為NULL,在執(zhí)行器關(guān)閉期間不會(huì)采取任何動(dòng)作。

INSERT或者COPY FROM插入到分區(qū)表中的元組會(huì)被路由到分區(qū)。如果一個(gè)FDW支持可路由的外部表分區(qū),它還應(yīng)該提供下面的回調(diào)函數(shù)。當(dāng)在外部表上執(zhí)行COPY FROM時(shí),也會(huì)調(diào)用這些函數(shù)。

void
BeginForeignInsert(ModifyTableState *mtstate,
                   ResultRelInfo *rinfo);

開始在外部表上執(zhí)行插入操作。當(dāng)外部表被選中作為元組路由的分區(qū)以及COPY FROM命令中指定的目標(biāo)時(shí),在第一個(gè)元組被插入到該外部表之前會(huì)調(diào)用這個(gè)例程。它應(yīng)該執(zhí)行實(shí)際插入之前所需的任何初始化工作。隨后,為每一個(gè)被插入到該外部表的元組都將調(diào)用ExecForeignInsert。

mtstate是正在被執(zhí)行的ModifyTable計(jì)劃節(jié)點(diǎn)的總體狀態(tài),通過這個(gè)結(jié)構(gòu)可以得到有關(guān)計(jì)劃和執(zhí)行的全局?jǐn)?shù)據(jù)。rinfo是描述目標(biāo)外部表的ResultRelInfo結(jié)構(gòu)(對(duì)于FDW,ResultRelInfori_FdwState字段用來存放這個(gè)操作所需要的私有狀態(tài))。

當(dāng)這個(gè)例程被一個(gè)COPY FROM命令調(diào)用時(shí),不會(huì)提供mtstate中與計(jì)劃相關(guān)的全局?jǐn)?shù)據(jù),并且后續(xù)為每個(gè)插入元組調(diào)用的ExecForeignInsertplanSlot參數(shù)為NULL,不管該外部表是為元組路由選中的分區(qū)還是命令中指定的目標(biāo)。

如果BeginForeignInsert指針被設(shè)置為NULL,則不會(huì)采取初始化動(dòng)作。

請(qǐng)注意如果 FDW 不支持在外表上的可路由外表分區(qū)和/或執(zhí)行 COPY FROM ,這個(gè)函數(shù)或 ExecForeignInsert 后續(xù)的調(diào)用必須根據(jù)需要發(fā)出錯(cuò)誤。

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

結(jié)束插入操作并且釋放資源。通常釋放palloc的內(nèi)存并不重要,但是打開的文件和與遠(yuǎn)程服務(wù)器的連接應(yīng)該被清除。

如果EndForeignInsert指針被設(shè)置為NULL,則不會(huì)采取終止動(dòng)作。

int
IsForeignRelUpdatable(Relation rel);

報(bào)告指定的外部表支持哪些更新操作。返回值應(yīng)該是一個(gè)規(guī)則事件編號(hào)的位掩碼,它指示了哪些操作被外部表支持,它使用CmdType枚舉,即: (1 << CMD_UPDATE) = 4表示UPDATE、 (1 << CMD_INSERT) = 8表示 INSERT以及 (1 << CMD_DELETE) = 16表示DELETE。

如果IsForeignRelUpdatable指針被設(shè)置為NULL,而FDW提供了ExecForeignInsertExecForeignUpdateExecForeignDelete,則外部表分別被假定為可插入、可更新或可刪除。只有在FDW支持某些表是可更新的而某些不是可更新的時(shí)候,才需要這個(gè)函數(shù)(即便如此,也允許在執(zhí)行例程中拋出一個(gè)錯(cuò)誤而不是在這個(gè)函數(shù)中檢查。但是,這個(gè)函數(shù)被用來決定顯示在 information_schema視圖中的可更新性)。

一些對(duì)于外部表的插入、更新和刪除可以通過實(shí)現(xiàn)另一組接口來優(yōu)化。普通的插入、更新和刪除接口會(huì)從遠(yuǎn)程服務(wù)器取得行,然后一次修改其中一行。在某些情況下,這種逐行的方式是必要的,但是可能效率不高。 如果有可能讓外部服務(wù)器判斷哪些行可以直接修改而無需先檢索它們,并且沒有本地結(jié)構(gòu)會(huì)影響該操作(行級(jí)本地觸發(fā)器,存儲(chǔ)生成的列, 或 來自父視圖的WITH CHECK OPTION約束。 那么可以讓整個(gè)操作在遠(yuǎn)程服務(wù)器上執(zhí)行。下面介紹的接口能讓這種做法變成可能。

bool
PlanDirectModify(PlannerInfo *root,
                 ModifyTable *plan,
                 Index resultRelation,
                 int subplan_index);

決定在遠(yuǎn)程服務(wù)器上執(zhí)行直接修改是否安全。如果安全,執(zhí)行所需的規(guī)劃動(dòng)作然后返回true。否則返回false。這個(gè)可選的函數(shù)在查詢規(guī)劃期間被調(diào)用。如果這個(gè)函數(shù)成功,在執(zhí)行階段將會(huì)調(diào)用BeginDirectModify、IterateDirectModifyEndDirectModify。否則,對(duì)表的修改將采用上文描述的表更新函數(shù)來執(zhí)行。參數(shù)和PlanForeignModify的相同。

要在遠(yuǎn)程服務(wù)器上執(zhí)行直接修改,這個(gè)函數(shù)必須用一個(gè)ForeignScan計(jì)劃節(jié)點(diǎn)(它在遠(yuǎn)程服務(wù)器上執(zhí)行直接修改)重寫目標(biāo)子計(jì)劃。ForeignScanoperation域必須被合適地設(shè)置為CmdType枚舉值,即CMD_UPDATE表示 UPDATECMD_INSERT表示INSERTCMD_DELETE表示DELETE。

更多信息請(qǐng)見第 56.4 節(jié)

如果PlanDirectModify指針被設(shè)置為NULL,不會(huì)嘗試在遠(yuǎn)程服務(wù)器上執(zhí)行直接修改。

void
BeginDirectModify(ForeignScanState *node,
                  int eflags);

準(zhǔn)備在遠(yuǎn)程服務(wù)器上執(zhí)行一次直接修改。這個(gè)函數(shù)會(huì)在執(zhí)行器啟動(dòng)時(shí)被調(diào)用。它應(yīng)該執(zhí)行直接修改所需的任何初始化工作(應(yīng)該在第一次IterateDirectModify調(diào)用之前完成)。ForeignScanState節(jié)點(diǎn)已經(jīng)被創(chuàng)建,但是它的fdw_state域仍然為 NULL。有關(guān)要被修改的表的信息可以通過 ForeignScanState節(jié)點(diǎn)(具體地,從底層的ForeignScan計(jì)劃節(jié)點(diǎn),它包含了PlanDirectModify提供的 FDW-私有信息)訪問。eflags包含描述執(zhí)行器對(duì)于這個(gè)計(jì)劃節(jié)點(diǎn)操作模式的標(biāo)志位。

注意當(dāng)(eflags & EXEC_FLAG_EXPLAIN_ONLY)為真時(shí),這個(gè)函數(shù)不應(yīng)該執(zhí)行任何外部可見的動(dòng)作。它應(yīng)當(dāng)只做最少的工作讓該節(jié)點(diǎn)狀態(tài)對(duì)ExplainDirectModifyEndDirectModify有效。

如果BeginDirectModify指針被設(shè)置為NULL,不會(huì)嘗試在遠(yuǎn)程服務(wù)器上執(zhí)行直接修改。

TupleTableSlot *
IterateDirectModify(ForeignScanState *node);

當(dāng)INSERT、UPDATE或者DELETE查詢沒有RETURNING子句時(shí),完成遠(yuǎn)程服務(wù)器上的直接修改后返回 NULL。當(dāng)查詢有該子句時(shí),取出一個(gè)包含RETURNING計(jì)算所需數(shù)據(jù)的結(jié)果,用一個(gè)元組表槽返回它(節(jié)點(diǎn)的 ScanTupleSlot應(yīng)被用于這一目的)。實(shí)際被插入、更新或者刪除的數(shù)據(jù)必須被存儲(chǔ)在該節(jié)點(diǎn)的EStatees_result_relation_info->ri_projectReturning->pi_exprContext->ecxt_scantuple中。如果沒有更多行可用,則返回 NULL。注意這個(gè)函數(shù)會(huì)在一個(gè)短期生存的內(nèi)存上下文中被調(diào)用,該上下文會(huì)在兩次調(diào)用之間被重置。如果需要一個(gè)長(zhǎng)期存在的存儲(chǔ),可以在 BeginDirectModify中創(chuàng)建一個(gè)內(nèi)存上下文,或者使用該節(jié)點(diǎn)的EState中的es_query_cxt

如果提供了fdw_scan_tlist目標(biāo)列表,則被返回的行必須匹配它。否則,被返回的行必須匹配被更新的外部表的行類型。如果選擇優(yōu)化掉RETURNING計(jì)算不需要的列,應(yīng)該在這些列的位置上插入空值,或者生成一個(gè)忽略這些列的fdw_scan_tlist列表。

不管該查詢是否具有RETURNING子句,查詢所報(bào)告的行計(jì)數(shù)必須由 FDW 本身增加。當(dāng)查詢沒有該子句時(shí),F(xiàn)DW 還必須為EXPLAIN ANALYZE情況下的ForeignScanState節(jié)點(diǎn)增加行計(jì)數(shù)。

如果IterateDirectModify指針被設(shè)置為NULL,不會(huì)嘗試在遠(yuǎn)程服務(wù)器上執(zhí)行直接修改。

void
EndDirectModify(ForeignScanState *node);

在遠(yuǎn)程服務(wù)器上的直接修改后進(jìn)行清理。通常釋放用 palloc 分配的內(nèi)存并不重要,但是諸如打開的文件和到遠(yuǎn)程服務(wù)器的連接應(yīng)該被清除。

如果EndDirectModify指針被設(shè)置為NULL,不會(huì)嘗試在遠(yuǎn)程服務(wù)器上執(zhí)行直接修改。

56.2.5. 用于行鎖定的 FDW 例程

如果一個(gè) FDW 希望支持后期行鎖定(如第 56.5 節(jié)中所述),它必須提供下列回調(diào)函數(shù):

RowMarkType
GetForeignRowMarkType(RangeTblEntry *rte,
                      LockClauseStrength strength);

報(bào)告要對(duì)一個(gè)外部表使用哪個(gè)行標(biāo)記選項(xiàng)。rte是該表的RangeTblEntry節(jié)點(diǎn),而strength描述FOR UPDATE/SHARE子句(如果有)所要求的鎖長(zhǎng)度。結(jié)果必須是RowMarkType枚舉類型的一個(gè)成員。

這個(gè)函數(shù)在查詢規(guī)劃期間會(huì)為每一個(gè)出現(xiàn)在UPDATEDELETE或者SELECT FOR UPDATE/SHARE查詢中的外部表調(diào)用,并且該外部表不是UPDATEDELETE的目標(biāo)。

如果GetForeignRowMarkType指針被設(shè)置為NULL,將總是使用ROW_MARK_COPY選項(xiàng)(這意味著將不會(huì)調(diào)用RefetchForeignRow,因此也不必提供它)。

更多信息請(qǐng)見第 56.5 節(jié)。

void
RefetchForeignRow(EState *estate,
                  ExecRowMark *erm,
                  Datum rowid,
                  TupleTableSlot *slot,
                  bool *updated);

從外部表中重新取得一個(gè)元組槽,如有必要先鎖定它。estate是該查詢的全局執(zhí)行狀態(tài)。erm是描述目標(biāo)外部表以及要獲取的行鎖類型(如果有)的ExecRowMark結(jié)構(gòu)。rowid標(biāo)識(shí)要取得的元組。 slot在調(diào)用時(shí)不包含有用內(nèi)容,但可用于保存返回的元組。 updated是一個(gè)輸出參數(shù)。

此函數(shù)應(yīng)將元組存儲(chǔ)到提供的槽中,或者在無法獲得行鎖時(shí)清除該槽。 要獲得的行鎖由erm->markType定義,它是之前由GetForeignRowMarkType返回的值(ROW_MARK_REFERENCE標(biāo)識(shí)只重新取得元組但不獲得任何鎖,這個(gè)例程將不會(huì)看到ROW_MARK_COPY)。

此外,如果取得的是一個(gè)更新過的版本而不是之前獲得的同一版本,*updated應(yīng)被設(shè)置為true(如果 FDW 無法確定這一點(diǎn),推薦總是返回true)。

注意在默認(rèn)情況下,獲取行鎖失敗應(yīng)該導(dǎo)致產(chǎn)生錯(cuò)誤。如果erm->waitPolicy指定了SKIP LOCKED,只有返回空槽才是合適的。

rowid是要被重新取得的行之前讀到的ctid值。盡管rowid值被作為Datum傳遞,但是目前它只能被讀作tid。選擇該函數(shù) API 是希望未來能允許其他的行 ID 數(shù)據(jù)類型。

如果RefetchForeignRow指針被設(shè)置為NULL,重新取得行的嘗試將會(huì)失敗并伴隨有一個(gè)錯(cuò)誤消息。

更多信息請(qǐng)見第 56.5 節(jié)

bool
RecheckForeignScan(ForeignScanState *node, TupleTableSlot *slot);

重新檢查之前返回的元組是否仍然匹配相關(guān)的掃描和連接條件,并且可能提供該元組的一個(gè)修改版本。對(duì)于不執(zhí)行連接下推的外部數(shù)據(jù)包裝器,通常把這設(shè)置為NULL并且恰當(dāng)?shù)卦O(shè)置fdw_recheck_quals會(huì)更方便。不過當(dāng)外部連接被下推時(shí),把與所有基表相關(guān)的檢查重新應(yīng)用在結(jié)果元組上是不夠的,即便所有需要的屬性都存在也是如此,因?yàn)槠ヅ淠硞€(gè)條件失敗可能會(huì)導(dǎo)致某些屬性變成 NULL,而不是沒有元組被返回。 RecheckForeignScan能夠重新檢查條件,并且在它們?nèi)匀粷M足時(shí)返回真,否則返回假,但是它也能夠在提供的槽中存儲(chǔ)一個(gè)替換元組。

要實(shí)現(xiàn)連接下推,外部數(shù)據(jù)包裝器通常將構(gòu)造一個(gè)可替代的本地連接計(jì)劃,它只被用來做重新檢查。這將變成ForeignScan的外子計(jì)劃。在需要一次重新檢查時(shí),這個(gè)子計(jì)劃可以被執(zhí)行并且結(jié)果元組可以被存儲(chǔ)在槽中。這個(gè)計(jì)劃不需要效率很高,因?yàn)椴粫?huì)有基表返回超過一行。例如,它可以把所有的連接實(shí)現(xiàn)為嵌套循環(huán)。函數(shù)GetExistingLocalJoinPath可以被用來在已有的路徑中搜索合適的本地連接路徑,它可以被用作替換的本地連接計(jì)劃。 GetExistingLocalJoinPath會(huì)在指定連接關(guān)系的路徑列表中搜索一個(gè)非參數(shù)化路徑(如果沒有找到這樣的路徑,它會(huì)返回 NULL,這種情況下外部數(shù)據(jù)包裝器可以自行構(gòu)造本地路徑或者可以選擇不為這個(gè)連接創(chuàng)建訪問路徑)。

56.2.6. EXPLAIN的FDW例程

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

為一個(gè)外部表掃描打印額外的EXPLAIN輸出。這個(gè)函數(shù)可以調(diào)用ExplainPropertyText和相關(guān)函數(shù)來向EXPLAIN輸出中增加域。es中的標(biāo)志域可以被用來決定什么將被打印,并且ForeignScanState節(jié)點(diǎn)的狀態(tài)可以被檢查來為 EXPLAIN ANALYZE提供運(yùn)行時(shí)統(tǒng)計(jì)數(shù)據(jù)。

如果ExplainForeignScan指針被設(shè)置為NULL,在EXPLAIN期間不會(huì)打印任何額外的信息。

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

為一個(gè)外部表更新打印額外的EXPLAIN輸出。這個(gè)函數(shù)可以調(diào)用ExplainPropertyText和相關(guān)函數(shù)來向EXPLAIN輸出中增加域。es中的標(biāo)志域可以被用來決定什么將被打印,并且ModifyTableState節(jié)點(diǎn)的狀態(tài)可以被檢查來為 EXPLAIN ANALYZE提供運(yùn)行時(shí)統(tǒng)計(jì)數(shù)據(jù)。前四個(gè)參數(shù)和BeginForeignModify相同。

如果ExplainForeignModify指針被設(shè)置為NULL,在EXPLAIN期間不會(huì)打印任何額外的信息。

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

為遠(yuǎn)程服務(wù)器上的直接修改打印額外的EXPLAIN輸出。這個(gè)函數(shù)可以調(diào)用ExplainPropertyText和相關(guān)函數(shù)來為EXPLAIN輸出增加域。es中的標(biāo)志域可以被用來判斷要打印什么,并且在EXPLAIN ANALYZE情況中可以觀察 ForeignScanState節(jié)點(diǎn)的狀態(tài)來提供運(yùn)行時(shí)統(tǒng)計(jì)信息。

如果ExplainDirectModify指針被設(shè)置為NULL,EXPLAIN期間不會(huì)打印出額外的信息。

56.2.7. ANALYZE的FDW例程

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

當(dāng)ANALYZE被執(zhí)行在一個(gè)外部表上時(shí)會(huì)調(diào)用這個(gè)函數(shù)。如果FDW可以為這個(gè)外部表收集統(tǒng)計(jì)信息,它會(huì)返回true并提供一個(gè)函數(shù)指針,該函數(shù)將將從func中的表上收集采樣行,外加 totalpages 中頁(yè)面中的表尺寸估計(jì)值。否則,返回false。

如果FDW不支持為任何表收集統(tǒng)計(jì)信息,AnalyzeForeignTable指針可以被設(shè)置為NULL。

如果提供,采樣收集函數(shù)必須具有簽名

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

應(yīng)該從該表上收集最多targrows行的一個(gè)隨機(jī)采樣并將它存放到調(diào)用者提供的rows數(shù)組中。實(shí)際被收集的行的數(shù)量必須被返回。另外,將表中有效行和死亡行的總數(shù)存儲(chǔ)到輸出參數(shù)totalrowstotaldeadrows中(如果FDW沒有死亡行的概念,將 totaldeadrows 設(shè)置為 0 )。

56.2.8. IMPORT FOREIGN SCHEMA的 FDW 例程

List *
ImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid);

取得一個(gè)外部表創(chuàng)建命令的列表。在執(zhí)行IMPORT FOREIGN SCHEMA時(shí)會(huì)調(diào)用這個(gè)函數(shù),并且會(huì)把該語句的解析樹以及要使用的外部服務(wù)器的 OID 傳遞給它。它應(yīng)該返回一個(gè) C 字符串的列表,每一個(gè)必須包含一個(gè)CREATE FOREIGN TABLE命令。這些命令將被核心服務(wù)器所解析和執(zhí)行。

ImportForeignSchemaStmt結(jié)構(gòu)中,remote_schema是要從其中導(dǎo)入這些表的遠(yuǎn)程模式的名稱。list_type標(biāo)識(shí)如何過濾表名:FDW_IMPORT_SCHEMA_ALL表示該遠(yuǎn)程模式中的所有表都應(yīng)該被導(dǎo)入(這種情況下 table_list為空),FDW_IMPORT_SCHEMA_LIMIT_TO表示只包括table_list中列出的表,而FDW_IMPORT_SCHEMA_EXCEPT則表示排除table_list中列出的表。options是一個(gè)用于該導(dǎo)入處理的選項(xiàng)列表。選項(xiàng)的含義由 FDW 決定。例如,一個(gè) FDW 可以用一個(gè)選項(xiàng)來定義是否應(yīng)該導(dǎo)入列的NOT NULL屬性。這些選項(xiàng)不需要與那些 FDW 支持的數(shù)據(jù)庫(kù)對(duì)象選項(xiàng)有什么關(guān)系。

FDW 可能會(huì)忽略ImportForeignSchemaStmtlocal_schema域,因?yàn)楹诵姆?wù)器會(huì)自動(dòng)地向解析好的CREATE FOREIGN TABLE命令中插入本地模式的名稱。

FDW 也不必?fù)?dān)心實(shí)現(xiàn)list_type以及table_list所指定的過濾,因?yàn)楹诵姆?wù)器將自動(dòng)根據(jù)那些選項(xiàng)跳過為被排除的表所返回的命令。不過,起初就避免為被排除的表創(chuàng)建命令當(dāng)然更好。函數(shù)IsImportableForeignTable()可以用來測(cè)試一個(gè)給定的外部表名是否能通過該過濾器。

如果 FDW 不支持導(dǎo)入表定義,ImportForeignSchema指針可以被設(shè)置為NULL。

56.2.9. 并行執(zhí)行的 FDW 例程

ForeignScan節(jié)點(diǎn)可以選擇支持并行執(zhí)行。一個(gè)并行的ForeignScan將在多個(gè)進(jìn)程中被執(zhí)行并且在相互合作的進(jìn)程中每一個(gè)元組必須只被返回一次。要做到這樣,進(jìn)程可以通過動(dòng)態(tài)共享內(nèi)存的固定尺寸塊來協(xié)作。并不保證在每一個(gè)進(jìn)程中這部份共享內(nèi)存都被映射到相同的地址,因此不能包含指針。下面的函數(shù)通常都是可選的,但是如果要支持并行執(zhí)行就必須提供其中的大部分。

bool
IsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel,
                          RangeTblEntry *rte);

測(cè)試一個(gè)掃描是否可以在一個(gè)并行工作者中被執(zhí)行。只有當(dāng)規(guī)劃器相信可以使用并行計(jì)劃時(shí)才會(huì)調(diào)用這個(gè)函數(shù),如果該掃描在并行工作者中可以安全運(yùn)行這個(gè)函數(shù)應(yīng)該返回真。如果遠(yuǎn)程數(shù)據(jù)源具有事務(wù)語義,情況通常都不是這樣,除非工作者到數(shù)據(jù)的連接能夠以某種方式共享與領(lǐng)導(dǎo)者相同的事務(wù)環(huán)境。

如果沒有定義這個(gè)函數(shù),則假定該掃描必須被放置在并行領(lǐng)導(dǎo)者中。注意返回真并不意味著該掃描本身可以被并行完成,只是說明該掃描可以在一個(gè)并行工作者中執(zhí)行。因此,即便當(dāng)不支持并行執(zhí)行時(shí),定義這個(gè)方法也是有用的。

Size
EstimateDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt);

估算并行操作所需的動(dòng)態(tài)共享內(nèi)存的數(shù)量。這可能比實(shí)際要用的數(shù)量更大,但是絕不能更小。返回值的單位是字節(jié)。這個(gè)函數(shù)是可選的,并且在不需要時(shí)可以省略。但是如果它被省略,接下來的三個(gè)函數(shù)也必須被省略,因?yàn)椴粫?huì)為FDW分配共享內(nèi)存。

void
InitializeDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt,
                         void *coordinate);

初始化并行操作所需的動(dòng)態(tài)共享內(nèi)存。coordinate指向一塊共享內(nèi)存區(qū)域,其尺寸等于EstimateDSMForeignScan的返回值。這個(gè)函數(shù)是可選的,并且在不需要時(shí)可以省略。

void
ReInitializeDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt,
                           void *coordinate);

當(dāng)外部掃描計(jì)劃將要被重新掃描時(shí),重新初始化并行操作所要求的動(dòng)態(tài)共享內(nèi)存。這個(gè)函數(shù)是可選的,并且在不需要時(shí)可以省略。推薦的措施是這個(gè)函數(shù)只重置共享狀態(tài),而ReScanForeignScan函數(shù)僅重置本地狀態(tài)。當(dāng)前,這個(gè)函數(shù)將在ReScanForeignScan之前被調(diào)用,但是最好不要依賴于這種順序。

void
InitializeWorkerForeignScan(ForeignScanState *node, shm_toc *toc,
                            void *coordinate);

基于領(lǐng)導(dǎo)者在InitializeDSMForeignScan期間建立的共享狀態(tài)初始化并行工作者的本地狀態(tài)。這個(gè)函數(shù)是可選的,并且在不需要時(shí)可以省略。

void
ShutdownForeignScan(ForeignScanState *node);

在預(yù)見到節(jié)點(diǎn)將不會(huì)被執(zhí)行完時(shí)釋放資源。這個(gè)函數(shù)不會(huì)在所有的情況中執(zhí)行,有時(shí)會(huì)在沒有先調(diào)用這個(gè)函數(shù)之前調(diào)用EndForeignScan。由于在這個(gè)回調(diào)被調(diào)用之后并行查詢使用的DSM段將被銷毀,希望在DMS段消失前采取某種行動(dòng)的外部數(shù)據(jù)包裝器應(yīng)該實(shí)現(xiàn)這個(gè)方法。

56.2.10. 用于路徑重新參數(shù)化的FDW例程

List *
ReparameterizeForeignPathByChild(PlannerInfo *root, List *fdw_private,
                                 RelOptInfo *child_rel);

在把一個(gè)由給定子關(guān)系child_rel的最頂層父關(guān)系參數(shù)化的路徑轉(zhuǎn)換成由該子關(guān)系參數(shù)化的路徑時(shí)會(huì)調(diào)用這個(gè)函數(shù)。該函數(shù)被用于重新參數(shù)化任意路徑或者轉(zhuǎn)化一個(gè)ForeignPath的給定fdw_private成員中保存的任意表達(dá)式節(jié)點(diǎn)。該回調(diào)可能會(huì)根據(jù)需要使用reparameterize_path_by_child、 adjust_appendrel_attrs或者adjust_appendrel_attrs_multilevel


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)