56.1. Создание нестандартных путей сканирования
Провайдер нестандартного сканирования обычно добавляет пути для базового отношения, установив следующий обработчик, который вызывается после того, как ядро системы построит, по её мнению, полный и корректный набор путей доступа для отношения.
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
задаёт битовую маску, которая должна включать флаг CUSTOMPATH_SUPPORT_BACKWARD_SCAN
, если нестандартный путь поддерживает сканирование назад, и CUSTOMPATH_SUPPORT_MARK_RESTORE
, если он поддерживает пометку позиции и её восстановление. Обе эти возможности являются факультативными. В необязательном поле 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;
Этот обработчик будет вызываться многократно для одного отношения соединения с разными сочетаниями внутренних и внешних отношений; задача обработчика — минимизировать при этом дублирующиеся операции.
56.1.1. Обработчики пути нестандартного сканирования
Plan *(*PlanCustomPath) (PlannerInfo *root, RelOptInfo *rel, CustomPath *best_path, List *tlist, List *clauses, List *custom_plans);
Преобразует нестандартный путь в законченный план. Возвращаемым значением обычно будет объект CustomScan
, который этот обработчик должен разместить в памяти и инициализировать. За подробностями обратитесь к Разделу 56.2.
void (*TextOutCustomPath) (StringInfo str, const CustomPath *node);
Выдаёт дополнительную информацию, когда для данного нестандартного узла вызывается nodeToString
. Этот обработчик является необязательным. Так как nodeToString
автоматически выводит все поля структуры, которые она видит, включая custom_private
, этот обработчик полезен, только если объект CustomPath
на самом деле внедрён в расширенную структуру, содержащую дополнительные поля.