PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

60.1. 创建自定义扫描路径 #

60.1.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 对象,并用 add_path(如果是部分路径则用 add_partial_path)把它们添加到 rel。自定义扫描提供者负责初始化 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,扫描节点只会被要求产生被扫描关系的 Var;如果设置了该标志,扫描节点必须能对这些 Var 求标量表达式的值。) 可选的 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 传入)随内外关系的组合而变化。为 joinrel 生成的 CustomPath 路径必须包含它所使用的连接子句集合;如果规划器把它选为 joinrel 的最佳路径,规划器会用这些子句把 CustomPath 路径转换为计划。

60.1.1. 自定义扫描路径回调 #

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

把自定义路径转换为完成的计划。返回值通常是一个 CustomScan 对象,回调必须分配并初始化它。更多细节见 Section 60.2。

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

当把由给定子关系 child_rel 最顶层父关系参数化的路径转换为被子关系参数化时,会调用此回调。该回调用于对保存在 CustomPath 的给定 custom_private 成员中的任何路径进行重参数化,或转换其中的任何表达式节点。回调可以按需使用 reparameterize_path_by_child、 adjust_appendrel_attrs 或 adjust_appendrel_attrs_multilevel。