59.1. Создание пользовательских путей сканирования#
59.1. Создание пользовательских путей сканирования #
Поставщик пользовательского сканирования обычно добавляет пути для базового отношения, устанавливая следующий хук, который вызывается после того, как основной код сгенерировал все возможные пути доступа для отношения (за исключением путей Gather и Gather Merge, которые создаются после этого вызова, чтобы они могли использовать частичные пути, добавленные хуком):
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
или
add_partial_path
, если это частичные пути.
Поставщик пользовательского сканирования отвечает за инициализацию
объекта CustomPath
, который объявляется следующим образом:
typedef struct CustomPath { Path path; uint32 flags; List *custom_paths; List *custom_restrictinfo; 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_restrictinfo
должен использоваться для хранения набора соединительных условий, применяемых к соединению, которое
заменяет пользовательский путь. В противном случае он должен быть NIL.
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;
Этот хук будет вызываться несколько раз для одного и того же соединения, с различными комбинациями внутренних и внешних соединений; ответственность за минимизацию дублированной работы лежит на хуке.
Обратите внимание, что набор соединительных условий, которые применяются к соединению, передается как extra->restrictlist
, варьируется в зависимости от комбинации внутренних и внешних отношений. Путь CustomPath
, созданный для joinrel
, должен содержать набор соединительных условий, которые он использует, и которые будут использованы планировщиком для преобразования пути CustomPath
в план, если он будет выбран планировщиком как лучший путь для joinrel
.
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
по мере необходимости.