一个自定义扫描提供者将通过设置下面的钩子函数来为基本关系增加路径, 在核心代码已经为该关系产生了所有访问路径集后(除了在此调用之后生成的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
对象并且使用add_path
把它们加入到rel
中。自定义扫描提供者负责初始化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;
对于同一个连接关系,这个钩子将被反复调用,因为要对不同的内外关系组合生成路径,所以如何最小化可能的重复工作是钩子函数的责任。
Plan *(*PlanCustomPath) (PlannerInfo *root, RelOptInfo *rel, CustomPath *best_path, List *tlist, List *clauses, List *custom_plans);
将一条自定义路径转换为一个完成的计划。返回值通常将是一个CustomScan
对象,回调函数必须负责分配并且初始化这个对象。详见第 61.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
。