59.1. Создание пользовательских путей сканирования#

59.1. Создание пользовательских путей сканирования

59.1. Создание пользовательских путей сканирования

Пользовательский поставщик сканирования обычно добавляет пути для базового отношения, устанавливая следующий хук, который вызывается после того, как основной код сгенерировал все доступные пути для отношения (за исключением путей Gather, которые создаются после этого вызова, чтобы они могли использовать частичные пути, добавленные хуком):

typedef void (*set_rel_pathlist_hook_type) (PlannerInfo *root,
                                            RelOptInfo *rel,
                                            Index rti,
                                            RangeTblEntry *rte);
extern PGDLLIMPORT set_rel_pathlist_hook_type set_rel_pathlist_hook;

Хотя эта функция-перехватчик может использоваться для изучения, изменения или удаления путей, созданных ядром системы, пользовательский поставщик сканирования обычно ограничивается генерацией объектов CustomPath и добавлением их в rel с использованием функции add_path. Пользовательский поставщик сканирования отвечает за инициализацию объекта CustomPath, который объявляется так:

typedef struct CustomPath
{
    Path      path;
    uint32    flags;
    List     *custom_paths;
    List     *custom_private;
    const CustomPathMethods *methods;
} CustomPath;

path должен быть инициализирован, как и любой другой путь, включая оценку количества строк, начальную и общую стоимость, а также порядок сортировки, предоставленный этим путем. flags - это битовая маска, которая указывает, может ли поставщик сканирования поддерживать определенные необязательные возможности. flags должен включать CUSTOMPATH_SUPPORT_BACKWARD_SCAN, если пользовательский путь может поддерживать обратное сканирование, CUSTOMPATH_SUPPORT_MARK_RESTORE, если он может поддерживать маркировку и восстановление, и CUSTOMPATH_SUPPORT_PROJECTION, если он может выполнять проекции. (Если CUSTOMPATH_SUPPORT_PROJECTION не установлен, узел сканирования будет просить только о создании Vars от сканируемого отношения; в то время как если этот флаг установлен, узел сканирования должен быть в состоянии оценить скалярные выражения над этими Vars.) Необязательный custom_paths - это список узлов Path, используемых этим пользовательским путем; они будут преобразованы в узлы Plan планировщиком. custom_private может быть использован для хранения приватных данных пользовательского пути. Приватные данные должны храниться в форме, которую может обрабатывать nodeToString, чтобы отладочные процедуры, пытающиеся распечатать пользовательский путь, работали как предполагалось. methods должен указывать на объект (обычно статически выделенный), реализующий требуемые методы пользовательского пути, которые детально описаны ниже.

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

typedef void (*set_join_pathlist_hook_type) (PlannerInfo *root,
                                             RelOptInfo *joinrel,
                                             RelOptInfo *outerrel,
                                             RelOptInfo *innerrel,
                                             JoinType jointype,
                                             JoinPathExtraData *extra);
extern PGDLLIMPORT set_join_pathlist_hook_type set_join_pathlist_hook;

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

59.1.1. Пользовательские обратные вызовы пути сканирования

Plan *(*PlanCustomPath) (PlannerInfo *root,
                         RelOptInfo *rel,
                         CustomPath *best_path,
                         List *tlist,
                         List *clauses,
                         List *custom_plans);

Преобразование пользовательского пути в готовый план. Обычно возвращаемым значением будет объект CustomScan, который обратный вызов должен выделить и инициализировать. См. Раздел 59.2 для получения более подробной информации.

List *(*ReparameterizeCustomPathByChild) (PlannerInfo *root,
                                          List *custom_private,
                                          RelOptInfo *child_rel);

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