openGauss添加create_upper_paths_hook方案
现状对比PostgreSQL 的架构- PG 使用 基于 Path 的统一规划模型所有阶段扫描、连接、聚合、排序、LIMIT都生成 Path最后选最优路径- create_upper_paths_hook 在 create_upper_paths() 中被调用每次处理一个 UpperRelationKind 阶段UPPERREL_GROUP_AGG、UPPERREL_WINDOW 等- 钩子接收的是 RelOptInfo*path 列表可以在 path 层面插入自定义路径如 FDW 远程聚合路径、TimescaleDB 的 gapfill 路径openGauss 的架构- openGauss 的 grouping_planner() 是 基于 Plan 节点的流水线不是 Path 层面的统一框架- 上层关系处理直接在 planner.cpp 中以硬编码的 if 分支完成GROUP BY →Window →DISTINCT →ORDER BY →LIMIT →Final- 已有扩展点a. FDWUpperRelCxt GetForeignUpperPaths_functionFDW 特有的 upper path 扩展机制通过 AdvanceFDWUpperPlan() 在每个阶段后通知 FDWb. planner_hook替换整个 planner 入口c. set_rel_pathlist_hook / set_join_pathlist_hook下层路径扩展d. get_relation_info_hook关系信息扩展e. for_tsdb_hook针对 hypertable INSERT 的专用钩子TimescaleDB 当前如何工作TimescaleDB 在 openGauss 中已经能正常工作因为它通过以下方式适配1. planner_hook 替换入口接管整个规划流程2. set_rel_pathlist_hook 在 set_rel_pathlist 阶段做 chunk 展开和 chunk_append 优化3. get_relation_info_hook 附加元数据4. for_tsdb_hook 处理 hypertable INSERT 的路径替换5. create_upper_paths_hook 虽然声明了在 tsdb_head.h 中但 openGauss 核心从不调用它——TimescaleDB自己保存/恢复这个全局变量但实际功能是通过其他钩子实现的推荐方案不建议直接移植 PG 的 create_upper_paths_hook 到 openGauss原因1. 语义不匹配PG 的 hook 操作的是 RelOptInfo.pathlistPath 级别openGauss 的规划器操作的是 Plan* 节点树Plan 级别。两者数据结构完全不同2. 侵入性太大需要在 openGauss 的 grouping_planner() 中大量插入钩子调用点改动面覆盖 GROUP/WINDOW/DISTINCT/ORDER/LIMIT 每个阶段3. 维护成本高每次 openGauss 升级都会产生大量 merge conflict最佳方案增强现有的 FDWUpperRelCxt 机制这是最自然的扩展点因为1. 已存在且成熟openGauss 已经在每个 upper 阶段GROUP_AGG、WINDOW、DISTINCT、ORDERED、LIMIT、FINAL之后调用 AdvanceFDWUpperPlan()这正是 PGcreate_upper_paths_hook 被调用的位置2. 接口已对齐GetForeignUpperPaths_function 的签名 (FDWUpperRelCxt*, UpperRelationKind, Plan*) 已经足够表达扩展意图3. 扩展成本低只需将 FDW 专用的机制泛化为通用钩子具体实现建议方案定义一个通用的 upper path hook 类型在 AdvanceFDWUpperPlan 的位置附近调用Step 1在planner.h中定义通用钩子类型// 在 src/include/optimizer/planner.h 中添加 typedef void (*create_upper_paths_hook_type) ( PlannerInfo* root, UpperRelationKind stage, Plan* mainPlan); extern THR_LOCAL PGDLLIMPORT create_upper_paths_hook_type create_upper_paths_hook;Step 2在planner.cpp的每个 upper 阶段后调用钩子在AdvanceFDWUpperPlan()调用之后、#ifdef STREAMPLAN分支之前增加if (create_upper_paths_hook ! NULL) { create_upper_paths_hook(root, UPPERREL_GROUP_AGG, result_plan); }对WINDOW、DISTINCT、ORDERED、LIMIT、FINAL各阶段都做同样处理。Step 3TimescaleDB 侧注册钩子TimescaleDB 的_planner_init()中prev_create_upper_paths_hook create_upper_paths_hook; create_upper_paths_hook timescale_create_upper_paths_hook;为什么这比直接移植 PG 的 hook 更好维度移植 PG hook增强 FDWUpperRelCxt改动范围需修改 grouping_planner() 多处引入新的 RelOptInfo 管理复用现有 AdvanceFDWUpperPlan 位置数据结构需要构造 RelOptInfo 给钩子无意义openGauss 不需要直接传 Plan*符合 openGauss 模型FDW 兼容可能与现有 FDW 机制冲突与 FDW 共享同一扩展点互补性能需要为 hook 构造中间结构零额外开销hook 返回即结束维护每次 PG 升级都要重新适配 hook 签名利用已有稳定的 FDW 扩展点关键洞察openGauss 的create_upper_paths_hook在 TimescaleDB 代码中之所以存在是因为 TimescaleDB 从 PG 移植时代码保留了 PG 的 hook 签名RelOptInfo*input/output。但在 openGauss 中这个 hook 从未被调用过——TimescaleDB 实际依赖的是set_rel_pathlist_hookfor_tsdb_hookplanner_hook。所以真正需要的不是一个 PG 风格的 hook而是一个 Plan 级别的 upper path 扩展点而AdvanceFDWUpperPlan的位置就是天然的选择。