56.2. Функции обратного вызова обертки внешних данных#

56.2. Функции обратного вызова обертки внешних данных

56.2. Функции обратного вызова обертки внешних данных #

Функция обработчика FDW возвращает структуру FdwRoutine, выделенную с помощью palloc, содержащую указатели на описанные ниже функции обратного вызова. Функции, связанные со сканированием, являются обязательными, остальные - необязательными.

Структурный тип FdwRoutine объявлен в файле src/include/foreign/fdwapi.h, см. его для получения дополнительной информации.

56.2.1. FDW процедуры для Сканирования Внешних Таблиц #

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

Получить оценки размера отношения для внешней таблицы. Это вызывается в начале планирования запроса, который сканирует внешнюю таблицу. root - это глобальная информация планировщика о запросе; baserel - информация планировщика об этой таблице; а foreigntableid - это OID внешней таблицы pg_class. (foreigntableid можно получить из структур данных планировщика, но он передается явно для экономии усилий).

Эта функция должна обновить baserel->rows до ожидаемого количества строк, возвращаемых сканированием таблицы, после учета фильтрации, выполненной ограничениями. Начальное значение baserel->rows является только постоянной оценкой по умолчанию, которую следует заменить, если это возможно. Функция также может выбрать обновление baserel->width, если она может вычислить более точную оценку средней ширины результирующей строки. (Начальное значение основано на типах данных столбцов и на средних значениях ширины столбцов, измеренных последней командой ANALYZE). Кроме того, эта функция может обновить baserel->tuples, если она может вычислить более точную оценку общего количества строк во внешней таблице. (Начальное значение берется из pg_class.reltuples, которое представляет общее количество строк, увиденных последней командой ANALYZE; оно будет равно -1, если на этой внешней таблице не выполнялась команда ANALYZE).

См. Раздел 56.4 для получения дополнительной информации.

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

Создает возможные пути доступа для сканирования внешней таблицы. Это вызывается во время планирования запроса. Параметры такие же, как и для функции GetForeignRelSize, которая уже была вызвана.

Эта функция должна генерировать как минимум один путь доступа (узел ForeignPath) для сканирования внешней таблицы и должна вызывать add_path для добавления каждого такого пути в baserel->pathlist. Рекомендуется использовать create_foreignscan_path для создания узлов ForeignPath. Функция может генерировать несколько путей доступа, например, путь, который имеет допустимые pathkeys для представления предварительно отсортированного результата. Каждый путь доступа должен содержать оценки стоимости, и может содержать любую приватную информацию FDW, которая необходима для идентификации конкретного метода сканирования.

См. Раздел 56.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), список целей, которые должны быть выведены узлом плана, ограничивающие предложения, которые должны быть применены узлом плана, и внешний подплан ForeignScan, который используется для повторных проверок, выполняемых RecheckForeignScan. (Если путь относится к соединению, а не к базовому отношению, foreigntableid равен InvalidOid).

Эта функция должна создавать и возвращать узел плана ForeignScan; рекомендуется использовать функцию make_foreignscan для построения узла ForeignScan.

См. Раздел 56.4 для получения дополнительной информации.

void
BeginForeignScan(ForeignScanState *node,
                 int eflags);

Начало выполнения внешнего сканирования. Это вызывается при запуске исполнителя. Оно должно выполнять любую необходимую инициализацию перед началом сканирования, но не начинать выполнение фактического сканирования (это должно быть сделано при первом вызове функции IterateForeignScan). Узел ForeignScanState уже был создан, но его поле fdw_state все еще равно NULL. Информация о таблице для сканирования доступна через узел ForeignScanState (в частности, из основного узла плана ForeignScan, который содержит любую частную информацию FDW, предоставленную функцией GetForeignPlan). eflags содержит флаги, описывающие режим работы исполнителя для данного узла плана.

Обратите внимание, что когда (eflags & EXEC_FLAG_EXPLAIN_ONLY) истинно, эта функция не должна выполнять никаких внешне видимых действий; она должна только выполнить минимально необходимые действия, чтобы сделать состояние узла допустимым для ExplainForeignScan и EndForeignScan.

TupleTableSlot *
IterateForeignScan(ForeignScanState *node);

Извлеките одну строку из внешнего источника и верните ее в слот таблицы кортежей (для этой цели следует использовать ScanTupleSlot узла). Верните NULL, если больше нет строк. Инфраструктура слота таблицы кортежей позволяет возвращать как физический, так и виртуальный кортеж; в большинстве случаев предпочтительнее второй вариант с точки зрения производительности. Обратите внимание, что это вызывается в контексте памяти с коротким сроком жизни, который будет сброшен между вызовами. Создайте контекст памяти в BeginForeignScan, если вам нужно хранение с более длительным сроком жизни, или используйте es_query_cxt узла EState.

Строки, возвращаемые, должны соответствовать целевому списку fdw_scan_tlist, если он был предоставлен, в противном случае они должны соответствовать типу строки сканируемой внешней таблицы. Если вы решите оптимизировать извлечение столбцов, которые не нужны, вы должны вставить значения NULL в эти позиции столбцов или сгенерировать список fdw_scan_tlist с не указанными этими столбцами.

Обратите внимание, что исполнитель Tantor BE не обращает внимания на то, нарушают ли возвращаемые строки какие-либо ограничения, определенные для внешней таблицы - но планировщик обращает внимание и может неправильно оптимизировать запросы, если во внешней таблице видны строки, которые не удовлетворяют объявленному ограничению. Если ограничение нарушается, когда пользователь заявил, что ограничение должно быть true, может быть целесообразно вызвать ошибку (как и в случае несоответствия типов данных).

void
ReScanForeignScan(ForeignScanState *node);

Перезапустите сканирование с самого начала. Обратите внимание, что значения любых параметров, от которых зависит сканирование, могут измениться, поэтому новое сканирование не обязательно вернет точно те же строки.

void
EndForeignScan(ForeignScanState *node);

Завершите сканирование и освободите ресурсы. Обычно не важно освобождать память, выделенную с помощью palloc, но, например, открытые файлы и соединения с удаленными серверами следует очистить.

56.2.2. FDW процедуры для Сканирования Внешних Соединений #

Если FDW поддерживает выполнение удаленного соединения (вместо извлечения данных обоих таблиц и выполнения соединения локально), он должен предоставить эту функцию обратного вызова:

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

Создайте возможные пути доступа для соединения двух (или более) внешних таблиц, которые все принадлежат одному внешнему серверу. Эта необязательная функция вызывается во время планирования запроса. Как и GetForeignPaths, эта функция должна генерировать путь(и) ForeignPath для предоставленного joinrel (используйте create_foreign_join_path для их построения) и вызывать add_path для добавления этих путей в набор путей, рассматриваемых для соединения. Но в отличие от GetForeignPaths, не обязательно, чтобы эта функция успешно создала хотя бы один путь, так как всегда возможны пути, включающие локальное соединение.

Обратите внимание, что эта функция будет вызываться несколько раз для одного и того же соединения с различными комбинациями внутренних и внешних отношений; ответственность за минимизацию дублированной работы лежит на FDW.

Если для соединения выбран путь ForeignPath, он будет представлять весь процесс соединения; пути, генерируемые для компонентных таблиц и вспомогательных соединений, не будут использоваться. Дальнейшая обработка пути соединения происходит примерно так же, как и для пути, сканирующего отдельную внешнюю таблицу. Одно отличие заключается в том, что поле scanrelid результирующего узла плана ForeignScan должно быть установлено в ноль, поскольку оно не представляет отдельное отношение; вместо этого поле fs_relids узла ForeignScan представляет набор соединенных отношений. (Последнее поле устанавливается автоматически кодом основного планировщика и не требует заполнения FDW.) Другое отличие заключается в том, что, поскольку список столбцов для удаленного соединения не может быть найден в системных каталогах, FDW должен заполнить поле fdw_scan_tlist соответствующим списком узлов TargetEntry, представляющих набор столбцов, которые он будет предоставлять во время выполнения возвращаемых им кортежей.

Примечание

Начиная с Tantor BE 16, fs_relids включает индексы таблицы диапазонов внешних соединений, если они были задействованы в этом соединении. Новое поле fs_base_relids включает только индексы базовых отношений, и таким образом имитирует старую семантику fs_relids.

См. Раздел 56.4 для получения дополнительной информации.

56.2.3. FDW процедуры для планирования пост-сканирования/соединения обработки #

Если FDW поддерживает выполнение удаленной обработки после сканирования/соединения, такую как удаленная агрегация, он должен предоставить эту функцию обратного вызова:

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

Создайте возможные пути доступа для обработки верхнего отношения, что является термином планировщика для всех операций обработки запроса после сканирования/соединения, таких как агрегация, оконные функции, сортировка и обновление таблицы. Эта необязательная функция вызывается во время планирования запроса. В настоящее время она вызывается только в том случае, если все базовые отношения, участвующие в запросе, принадлежат одному внешнему источнику данных (FDW). Эта функция должна генерировать пути ForeignPath для любой операции обработки после сканирования/соединения, которую FDW может выполнить удаленно (используйте create_foreign_upper_path для их создания) и вызывать add_path для добавления этих путей в указанное верхнее отношение. Как и в случае с GetForeignJoinPaths, не обязательно, чтобы эта функция успешно создала какие-либо пути, так как всегда возможны пути с локальной обработкой.

Параметр stage определяет, какой шаг после сканирования/соединения в данный момент рассматривается. output_rel - это верхнее отношение, которое должно получить пути, представляющие вычисление этого шага, а input_rel - это отношение, представляющее входные данные для этого шага. Параметр extra предоставляет дополнительные детали, в настоящее время он устанавливается только для UPPERREL_PARTIAL_GROUP_AGG или UPPERREL_GROUP_AGG, в этом случае он указывает на структуру GroupPathExtraData; или для UPPERREL_FINAL, в этом случае он указывает на структуру FinalPathExtraData. (Обратите внимание, что пути ForeignPath, добавленные в output_rel, обычно не имеют прямой зависимости от путей input_rel, поскольку их обработка ожидается внешней. Однако, изучение ранее сгенерированных путей для предыдущего шага обработки может быть полезным для избежания избыточной работы по планированию).

См. Раздел 56.4 для получения дополнительной информации.

56.2.4. FDW процедуры для обновления внешних таблиц #

Если FDW поддерживает записываемые внешние таблицы, он должен предоставить некоторые или все из следующих функций обратного вызова в зависимости от потребностей и возможностей FDW:

void
AddForeignUpdateTargets(PlannerInfo *root,
                        Index rtindex,
                        RangeTblEntry *target_rte,
                        Relation target_relation);

UPDATE и DELETE операции выполняются против строк, ранее выбранных функциями сканирования таблицы. Внешний поставщик данных может потребовать дополнительной информации, такой как идентификатор строки или значения первичных ключей, чтобы убедиться, что он может идентифицировать точную строку для обновления или удаления. Для поддержки этого, эта функция может добавить дополнительные скрытые, или мусорные, целевые столбцы в список столбцов, которые должны быть извлечены из внешней таблицы во время UPDATE или DELETE.

Для этого создайте Var, представляющий дополнительное значение, которое вам нужно, и передайте его в add_row_identity_var, вместе с именем для мусорного столбца. (Вы можете сделать это несколько раз, если требуется несколько столбцов). Вы должны выбрать отдельное имя мусорного столбца для каждого различного Var, которое вам нужно, за исключением того, что Var, идентичные за исключением поля varno, могут и должны использовать одно и то же имя столбца. Ядро системы использует имена мусорных столбцов tableoid для столбца tableoid таблицы, ctid или ctidN для ctid, wholerow для целой строки Var, помеченной vartype = RECORD, и wholerowN для целой строки Var с vartype, равным объявленному типу строки таблицы. Используйте эти имена, когда это возможно (планировщик объединит дублирующиеся запросы на идентичные мусорные столбцы). Если вам нужен другой вид мусорного столбца помимо этих, мудро будет выбрать имя с префиксом вашего расширения, чтобы избежать конфликтов с другими FDW.

Если указатель AddForeignUpdateTargets установлен в NULL, дополнительные выражения целей не добавляются. (Это сделает невозможным реализацию операций DELETE, хотя UPDATE все еще может быть выполнимым, если FDW полагается на неизменный первичный ключ для идентификации строк).

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

Выполните все необходимые дополнительные действия планирования для вставки, обновления или удаления во внешней таблице. Эта функция генерирует приватную информацию FDW, которая будет прикреплена к узлу плана ModifyTable, выполняющему действие обновления. Эта приватная информация должна иметь форму List и будет передана в BeginForeignModify на этапе выполнения.

root - это глобальная информация планировщика о запросе. plan - это узел плана ModifyTable, который полностью готов, за исключением поля fdwPrivLists. resultRelation идентифицирует целевую внешнюю таблицу по ее индексу в таблице диапазона. subplan_index указывает, какая цель узла плана ModifyTable это, считая с нуля; используйте это, если нужно индексировать в подструктуры отношений для каждой цели узла plan.

См. Раздел 56.4 для получения дополнительной информации.

Если указатель PlanForeignModify установлен в NULL, дополнительные действия на этапе планирования не выполняются, и список fdw_private, переданный в BeginForeignModify, будет равен NIL.

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

Начало выполнения операции модификации внешней таблицы. Эта процедура вызывается при запуске исполнителя. Она должна выполнить любую необходимую инициализацию перед фактическими модификациями таблицы. В дальнейшем будут вызваны функции ExecForeignInsert/ExecForeignBatchInsert, ExecForeignUpdate или ExecForeignDelete для вставки, обновления или удаления кортежей.

mtstate - это общее состояние узла плана ModifyTable, который выполняется; глобальные данные о плане и состоянии выполнения доступны через эту структуру. rinfo - это структура ResultRelInfo, описывающая целевую внешнюю таблицу. (Поле ri_FdwState структуры ResultRelInfo доступно для хранения любого частного состояния 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 на внешней таблице, в котором случае она вызывается по-другому, чем в случае INSERT. См. описанные ниже обратные вызовы, которые позволяют FDW поддерживать это.

TupleTableSlot **
ExecForeignBatchInsert(EState *estate,
                       ResultRelInfo *rinfo,
                       TupleTableSlot **slots,
                       TupleTableSlot **planSlots,
                       int *numSlots);

Вставьте несколько кортежей массово во внешнюю таблицу. Параметры для ExecForeignInsert такие же, за исключением того, что slots и planSlots содержат несколько кортежей, а *numSlots указывает количество кортежей в этих массивах.

Возвращаемое значение представляет собой массив слотов, содержащих данные, которые были фактически вставлены (это может отличаться от предоставленных данных, например, в результате действий триггера). Переданные слоты slots могут быть использованы повторно для этой цели. Количество успешно вставленных кортежей возвращается в *numSlots.

Данные в возвращаемом слоте используются только в том случае, если оператор INSERT включает представление WITH CHECK OPTION; или если у внешней таблицы есть триггер AFTER ROW. Триггеры требуют все столбцы, но FDW может выбрать оптимизацию и не возвращать некоторые или все столбцы в зависимости от содержимого ограничений WITH CHECK OPTION.

Если указатель ExecForeignBatchInsert или GetForeignModifyBatchSize установлен в NULL, попытки вставки во внешнюю таблицу будут использовать функцию ExecForeignInsert. Эта функция не используется, если у INSERT есть фраза RETURNING.

Обратите внимание, что эта функция также вызывается при вставке маршрутизированных кортежей в секцию внешней таблицы или выполнении COPY FROM на внешней таблице, в котором случае она вызывается по-другому, чем в случае 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, описывающая целевую внешнюю таблицу. (Поле ri_FdwState структуры ResultRelInfo доступно для хранения любого частного состояния, необходимого для этой операции, внешним модулем обработки данных (FDW).)

Когда это вызывается командой COPY FROM, глобальные данные, связанные с планом, в mtstate не предоставляются, и параметр planSlot функции ExecForeignInsert, вызываемой для каждой вставленной кортежа, равен NULL, независимо от того, является ли внешняя таблица выбранной для маршрутизации кортежа или целевой таблицей, указанной в команде.

Если указатель BeginForeignInsert установлен в NULL, то инициализация не выполняется.

Обратите внимание, что если FDW не поддерживает размещение внешних таблиц по маршруту и/или выполнение COPY FROM на внешних таблицах, эта функция или ExecForeignInsert/ExecForeignBatchInsert, вызванная впоследствии, должна выбрасывать ошибку при необходимости.

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

Завершите операцию вставки и освободите ресурсы. Обычно не важно освобождать память, выделенную с помощью palloc, но, например, открытые файлы и соединения с удаленными серверами следует очистить.

Если указатель EndForeignInsert установлен в NULL, то никаких действий не выполняется при завершении.

int
IsForeignRelUpdatable(Relation rel);

Отчет о том, какие операции обновления поддерживает указанная внешняя таблица. Возвращаемое значение должно быть битовой маской номеров событий правил, указывающих какие операции поддерживаются внешней таблицей, используя перечисление CmdType; то есть, (1 << CMD_UPDATE) = 4 для UPDATE, (1 << CMD_INSERT) = 8 для INSERT, и (1 << CMD_DELETE) = 16 для DELETE.

Если указатель IsForeignRelUpdatable установлен в NULL, предполагается, что внешние таблицы могут быть вставлены, обновлены или удалены, если FDW предоставляет функции 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, который выполняет прямое изменение на удаленном сервере. Поля operation и resultRelation в ForeignScan должны быть установлены соответствующим образом. Поле operation должно быть установлено на перечисление CmdType, соответствующее виду оператора (то есть CMD_UPDATE для UPDATE, CMD_INSERT для INSERT и CMD_DELETE для DELETE), а аргумент resultRelation должен быть скопирован в поле resultRelation.

См. Раздел 56.4 для получения дополнительной информации.

Если указатель PlanDirectModify установлен в NULL, то не предпринимаются попытки выполнить прямое изменение на удаленном сервере.

void
BeginDirectModify(ForeignScanState *node,
                  int eflags);

Подготовка к выполнению прямого изменения на удаленном сервере. Это вызывается во время запуска исполнителя. Он должен выполнить любую инициализацию, необходимую перед прямым изменением (которое должно быть выполнено при первом вызове функции IterateDirectModify). Узел ForeignScanState уже был создан, но его поле fdw_state все еще равно NULL. Информация о таблице для изменения доступна через узел ForeignScanState (в частности, из основного узла плана ForeignScan, который содержит любую частную информацию FDW, предоставленную функцией PlanDirectModify). eflags содержит флаги, описывающие режим работы исполнителя для этого узла плана.

Обратите внимание, что когда (eflags & EXEC_FLAG_EXPLAIN_ONLY) истинно, эта функция не должна выполнять никаких внешне видимых действий; она должна только выполнить минимально необходимые действия, чтобы сделать состояние узла допустимым для ExplainDirectModify и EndDirectModify.

Если указатель BeginDirectModify установлен в NULL, то не предпринимаются попытки выполнить прямое изменение на удаленном сервере.

TupleTableSlot *
IterateDirectModify(ForeignScanState *node);

Когда запрос INSERT, UPDATE или DELETE не содержит предложение RETURNING, просто возвращайте NULL после прямого изменения на удаленном сервере. Когда запрос содержит это предложение, извлеките один результат, содержащий данные, необходимые для вычисления RETURNING, и верните его в слот таблицы кортежей (для этой цели следует использовать поле ScanTupleSlot узла). Данные, которые были фактически вставлены, обновлены или удалены, должны быть сохранены в node->resultRelInfo->ri_projectReturning->pi_exprContext->ecxt_scantuple. Верните NULL, если больше нет строк. Обратите внимание, что это вызывается в контексте памяти с коротким сроком жизни, который будет сброшен между вызовами. Создайте контекст памяти в функции BeginDirectModify, если вам нужно хранение с более длительным сроком жизни, или используйте поле es_query_cxt узла EState.

Строки, возвращаемые, должны соответствовать целевому списку fdw_scan_tlist, если он был предоставлен, в противном случае они должны соответствовать типу строки внешней таблицы, которая обновляется. Если вы решите оптимизировать извлечение столбцов, которые не нужны для вычисления RETURNING, вы должны вставить null в эти позиции столбцов или сгенерировать список fdw_scan_tlist с не указанными этими столбцами.

Независимо от того, есть ли в запросе данная фраза или нет, количество строк, сообщаемое запросом, должно быть увеличено самим FDW. Когда в запросе нет данной фразы, FDW также должен увеличить количество строк для узла ForeignScanState в случае EXPLAIN ANALYZE.

Если указатель IterateDirectModify установлен в NULL, то не предпринимаются попытки выполнить прямое изменение на удаленном сервере.

void
EndDirectModify(ForeignScanState *node);

Очистка после прямого изменения на удаленном сервере. Обычно не важно освобождать память, выделенную с помощью palloc, но, например, открытые файлы и соединения с удаленным сервером должны быть очищены.

Если указатель EndDirectModify установлен в NULL, то не предпринимаются попытки выполнить прямое изменение на удаленном сервере.

56.2.5. FDW процедуры для TRUNCATE #

void
ExecForeignTruncate(List *rels,
                    DropBehavior behavior,
                    bool restart_seqs);

Обрезать внешние таблицы. Эта функция вызывается при выполнении команды TRUNCATE на внешней таблице. rels - это список структур данных Relation внешних таблиц, которые нужно обрезать.

behavior может быть либо DROP_RESTRICT, либо DROP_CASCADE, указывающее на то, что опция RESTRICT или CASCADE была запрошена в исходной команде TRUNCATE, соответственно.

Если restart_seqs равно true, исходная команда TRUNCATE запрашивает поведение RESTART IDENTITY, в противном случае запрашивается поведение CONTINUE IDENTITY.

Обратите внимание, что ONLY опции, указанные в исходной команде TRUNCATE, не передаются в ExecForeignTruncate. Это поведение аналогично функциям обратного вызова SELECT, UPDATE и DELETE на внешней таблице.

ExecForeignTruncate вызывается один раз для каждого внешнего сервера, для которого требуется очистка внешних таблиц. Это означает, что все внешние таблицы, включенные в rels, должны принадлежать одному серверу.

Если указатель ExecForeignTruncate установлен в NULL, попытки обрезать внешние таблицы завершатся с ошибкой и будет выведено сообщение об ошибке.

56.2.6. FDW процедуры для блокировки строк #

Если FDW хочет поддерживать позднюю блокировку строк (как описано в Раздел 56.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 никогда не будет вызываться, поэтому его также необходимо предоставлять).

См. Раздел 56.5 для получения дополнительной информации.

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

Повторно получить один слот кортежа из внешней таблицы, после его блокировки, если это требуется. estate - это глобальное состояние выполнения запроса. erm - это структура ExecRowMark, описывающая целевую внешнюю таблицу и тип блокировки строки (если есть), которую нужно получить. rowid идентифицирует кортеж, который нужно получить. slot не содержит ничего полезного при вызове, но может использоваться для хранения полученного кортежа. updated - это выходной параметр.

Эта функция должна сохранить кортеж в предоставленный слот или очистить его, если не удалось получить блокировку строки. Тип блокировки строки, который нужно получить, определяется значением erm->markType, которое было ранее возвращено функцией GetForeignRowMarkType. (ROW_MARK_REFERENCE означает просто повторное извлечение кортежа без получения блокировки, а ROW_MARK_COPY никогда не будет использоваться этой процедурой).

Кроме того, *updated должно быть установлено в true, если полученная кортежа является обновленной версией, а не той же версией, которая была получена ранее. (Если FDW не может быть уверен в этом, рекомендуется всегда возвращать true).

Обратите внимание, что по умолчанию, неудачная попытка получить блокировку строки должна приводить к возникновению ошибки; возвращение с пустым слотом является допустимым только в том случае, если опция SKIP LOCKED указана в erm->waitPolicy.

The rowid - это значение ctid, прочитанное ранее для строки, которую нужно повторно получить. Хотя значение rowid передается как Datum, в настоящее время оно может быть только tid. Функциональный интерфейс выбран в надежде, что в будущем будет возможно разрешить использование других типов данных для идентификаторов строк.

Если указатель RefetchForeignRow установлен в NULL, попытки повторного получения строк завершатся с ошибкой и выводом сообщения об ошибке.

См. Раздел 56.5 для получения дополнительной информации.

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

Проверьте, что ранее возвращенный кортеж по-прежнему соответствует соответствующим условиям сканирования и соединения, и, возможно, предоставьте измененную версию кортежа. Для оберток внешних данных, которые не выполняют оптимизацию соединения, обычно удобнее установить это значение в NULL и соответствующим образом установить fdw_recheck_quals. Однако, когда внешние соединения выполняются вниз, недостаточно повторно применить проверки, относящиеся ко всем базовым таблицам, к результату кортежа, даже если все необходимые атрибуты присутствуют, потому что несоответствие некоторого условия может привести к тому, что некоторые атрибуты станут NULL, а не к тому, что кортеж не будет возвращен. RecheckForeignScan может повторно проверить условия и вернуть true, если они по-прежнему выполняются, и false в противном случае, но он также может сохранить замену кортежа в предоставленном слоте.

Для реализации передачи соединения, обертка внешних данных обычно создает альтернативный локальный план соединения, который используется только для повторных проверок; это становится внешним подпланом ForeignScan. Когда требуется повторная проверка, этот подплан может быть выполнен, и полученный кортеж может быть сохранен в слоте. Этот план не обязан быть эффективным, так как ни одна базовая таблица не вернет более одной строки; например, он может реализовывать все соединения в виде вложенных циклов. Функция GetExistingLocalJoinPath может использоваться для поиска существующих путей для подходящего локального пути соединения, который может быть использован в качестве альтернативного локального плана соединения. GetExistingLocalJoinPath ищет непараметризованный путь в списке путей указанного соединения. (Если такой путь не найден, он возвращает NULL, в этом случае обертка внешних данных может самостоятельно создать локальный путь или может выбрать не создавать доступные пути для этого соединения).

56.2.7. FDW процедуры для EXPLAIN #

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

Выводить дополнительную информацию EXPLAIN для сканирования внешней таблицы. Эта функция может вызывать ExplainPropertyText и связанные функции для добавления полей в вывод EXPLAIN. Флаги в es могут использоваться для определения того, что выводить, и состояние узла ForeignScanState может быть проверено для предоставления статистики выполнения в случае использования EXPLAIN ANALYZE.

Если указатель ExplainForeignScan установлен в NULL, дополнительная информация не будет выводиться во время EXPLAIN.

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

Выводить дополнительную информацию EXPLAIN для обновления внешней таблицы. Эта функция может вызывать ExplainPropertyText и связанные функции для добавления полей в вывод EXPLAIN. Флаги в es могут использоваться для определения того, что выводить, и состояние узла ModifyTableState может быть проверено для предоставления статистики выполнения в случае использования EXPLAIN ANALYZE. Первые четыре аргумента такие же, как для BeginForeignModify.

Если указатель ExplainForeignModify установлен в NULL, дополнительная информация не выводится во время EXPLAIN.

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

Выводите дополнительную информацию EXPLAIN для прямого изменения на удаленном сервере. Эта функция может вызывать ExplainPropertyText и связанные функции для добавления полей в вывод EXPLAIN. Флаговые поля в es могут использоваться для определения того, что нужно печатать, и состояние узла ForeignScanState может быть проверено для предоставления статистики времени выполнения в случае использования EXPLAIN ANALYZE.

Если указатель ExplainDirectModify установлен в NULL, дополнительная информация не будет выводиться во время EXPLAIN.

56.2.8. FDW процедуры для ANALYZE #

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

Эта функция вызывается, когда выполняется ANALYZE на внешней таблице. Если FDW может собирать статистику для этой внешней таблицы, он должен вернуть true и предоставить указатель на функцию, которая будет собирать образцовые строки из таблицы в func, а также оценочный размер таблицы в страницах в totalpages. В противном случае вернуть false.

Если FDW не поддерживает сбор статистики для каких-либо таблиц, указатель AnalyzeForeignTable может быть установлен в значение NULL.

Если предоставлено, функция сбора образца должна иметь сигнатуру

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

Следует собрать случайную выборку из до targrows строк из таблицы и сохранить их в предоставленный вызывающей стороной массив rows. Фактическое количество собранных строк должно быть возвращено. Кроме того, оценки общего количества активных и удаленных строк в таблице должны быть сохранены в выходных параметрах totalrows и totaldeadrows. (Установите totaldeadrows в ноль, если FDW не имеет понятия об удаленных строках).

56.2.9. FDW процедуры для IMPORT FOREIGN SCHEMA #

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 может игнорировать поле local_schema в ImportForeignSchemaStmt, поскольку ядро сервера автоматически вставляет это имя в разобранные команды CREATE FOREIGN TABLE.

FDW не должен беспокоиться о реализации фильтрации, указанной в list_type и table_list, так как ядро сервера автоматически пропускает любые возвращаемые команды для таблиц, исключенных в соответствии с этими опциями. Однако часто полезно избежать работы по созданию команд для исключенных таблиц в первую очередь. Функция IsImportableForeignTable() может быть полезна для проверки, пройдет ли заданное имя внешней таблицы фильтр.

Если FDW не поддерживает импорт определений таблиц, указатель ImportForeignSchema может быть установлен в NULL.

56.2.10. FDW процедуры для Параллельного Выполнения #

Узел ForeignScan может, по желанию, поддерживать параллельное выполнение. Параллельный ForeignScan будет выполняться в нескольких процессах и должен возвращать каждую строку ровно один раз во всех взаимодействующих процессах. Для этого процессы могут согласовываться через фиксированные части динамической общей памяти. Эта общая память не гарантирует, что она будет отображена по тому же адресу в каждом процессе, поэтому она не должна содержать указателей. Все перечисленные ниже функции являются необязательными, но большинство из них требуется для поддержки параллельного выполнения.

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

Проверьте, может ли быть выполнено сканирование внутри параллельного рабочего процесса. Эта функция будет вызвана только тогда, когда планировщик считает возможным параллельное планирование, и должна вернуть true, если это безопасно для выполнения сканирования внутри параллельного рабочего процесса. Это обычно не будет возможно, если удаленный источник данных имеет семантику транзакций, если только соединение рабочего процесса с данными не может быть как-то сделано для совместного использования того же контекста транзакции, что и у лидера.

Если эта функция не определена, предполагается, что сканирование должно происходить внутри параллельного лидера. Обратите внимание, что возвращение значения true не означает, что само сканирование может выполняться параллельно, а только то, что сканирование может быть выполнено внутри параллельного рабочего процесса. Поэтому может быть полезно определить этот метод, даже когда параллельное выполнение не поддерживается.

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

Оцените количество динамической общей памяти, которая будет необходима для параллельной работы. Это значение может быть выше, чем фактически используемое количество, но не должно быть меньше. Возвращаемое значение указано в байтах. Эта функция является необязательной и можно опустить, если не требуется; но если она не указана, следующие три функции также должны быть не указаны, потому что для использования FDW не будет выделена общая память.

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

Инициализируйте динамическую общую память, которая будет необходима для параллельной работы. coordinate указывает на область общей памяти размером, равным возвращаемому значению функции EstimateDSMForeignScan. Эта функция является необязательной и можно опустить, если она не требуется.

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

Переинициализируйте динамическую общую память, необходимую для параллельной работы, когда узел плана foreign-scan должен быть повторно отсканирован. Эта функция является необязательной и можно опустить, если не требуется. Рекомендуется, чтобы эта функция сбрасывала только общее состояние, в то время как функция ReScanForeignScan сбрасывает только локальное состояние. В настоящее время эта функция будет вызвана перед ReScanForeignScan, но лучше не полагаться на этот порядок.

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

Инициализирует локальное состояние параллельного рабочего процесса на основе общего состояния, установленного лидером во время InitializeDSMForeignScan. Эта функция является необязательной и можно опустить, если не требуется.

void
ShutdownForeignScan(ForeignScanState *node);

Освободите ресурсы, когда ожидается, что узел не будет выполнен до конца. Это не вызывается во всех случаях; иногда EndForeignScan может быть вызван без предварительного вызова этой функции. Поскольку сегмент DSM, используемый параллельным запросом, уничтожается сразу после вызова этого обратного вызова, обертки внешних данных, которые хотят выполнить некоторые действия перед уничтожением сегмента DSM, должны реализовать этот метод.

56.2.11. FDW процедуры для асинхронного выполнения #

Узел ForeignScan может, по желанию, поддерживать асинхронное выполнение, как описано в файле src/backend/executor/README. Следующие функции все являются необязательными, но все они необходимы для поддержки асинхронного выполнения.

bool
IsForeignPathAsyncCapable(ForeignPath *path);

Проверяет, может ли данный путь ForeignPath сканировать базовое внешнее отношение асинхронно. Эта функция будет вызвана только в конце планирования запроса, когда данный путь является прямым наследником пути AppendPath и когда планировщик считает, что асинхронное выполнение улучшает производительность, и должна возвращать true, если данный путь может сканировать внешнее отношение асинхронно.

Если эта функция не определена, предполагается, что указанный путь сканирует внешнее отношение с помощью функции IterateForeignScan. (Это означает, что описанные ниже функции обратного вызова никогда не будут вызываться, поэтому их также не нужно предоставлять).

void
ForeignAsyncRequest(AsyncRequest *areq);

Асинхронно производит одну кортеж из узла ForeignScan. areq - это структура AsyncRequest, описывающая узел ForeignScan и родительский узел Append, который запросил кортеж из него. Эта функция должна сохранить кортеж в слоте, указанном в areq->result, и установить areq->request_complete в true; или, если она должна ожидать события внешнего от ядра сервера, такого как сетевой ввод-вывод, и не может немедленно произвести кортеж, установить флаг в false, и установить areq->callback_pending в true для узла ForeignScan, чтобы получить обратный вызов от описанных ниже функций обратного вызова. Если больше нет доступных кортежей, установите слот в NULL или пустой слот, и флаг areq->request_complete в true. Рекомендуется использовать функции ExecAsyncRequestDone или ExecAsyncRequestPending для установки выходных параметров в areq.

void
ForeignAsyncConfigureWait(AsyncRequest *areq);

Настроить событие файлового дескриптора, на которое узел ForeignScan хочет ожидать. Эта функция будет вызвана только тогда, когда узел ForeignScan имеет установленный флаг areq->callback_pending и должна добавить событие в as_eventset родительского узла Append, описанного areq. Дополнительную информацию см. в комментариях к функции ExecAsyncConfigureWait в файле src/backend/executor/execAsync.c. При возникновении события файлового дескриптора будет вызвана функция ForeignAsyncNotify.

void
ForeignAsyncNotify(AsyncRequest *areq);

Обработайте соответствующее событие, которое произошло, затем асинхронно создайте одну кортеж из узла ForeignScan. Эта функция должна установить выходные параметры в areq так же, как и ForeignAsyncRequest.

56.2.12. FDW процедуры для перепараметризации путей #

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

Эта функция вызывается при преобразовании пути, параметризованного верхним родительским отношением заданного дочернего отношения child_rel, чтобы параметризовать его дочерним отношением. Функция используется для повторного параметризации любых путей или перевода любых сохраненных узлов выражений в члене fdw_private структуры ForeignPath. Обратный вызов может использовать reparameterize_path_by_child, adjust_appendrel_attrs или adjust_appendrel_attrs_multilevel по необходимости.