自定义扫描在完成的计划树中用以下结构表示:
typedef struct CustomScan
{
Scan scan;
uint32 flags;
List *custom_plans;
List *custom_exprs;
List *custom_private;
List *custom_scan_tlist;
Bitmapset *custom_relids;
const CustomScanMethods *methods;
} CustomScan;
scan 必须像任何其他扫描一样初始化,包括估算代价、目标列表、条件等。
flags 是一个位掩码,含义与
CustomPath 中相同。
custom_plans 可用于存储子
Plan 节点。
custom_exprs 应被用来存储需要由
setrefs.c 与
subselect.c 修正的表达式树,而
custom_private 应被用来存储只由自定义扫描提供者自身使用的其他私有数据。
custom_scan_tlist 在扫描基础关系时可以为 NIL,表示自定义扫描返回与该基础关系行类型匹配的扫描元组。否则它是一个描述实际扫描元组的目标列表。对连接必须提供
custom_scan_tlist;如果自定义扫描提供者能计算某些非 Var 表达式,对扫描也可以提供。
custom_relids 由核心代码设置为该扫描节点处理的关系(范围表索引)集合;除非该扫描正在替代一个连接,否则它将只有一个成员。
methods 必须指向一个(通常是静态分配的)实现所需自定义扫描方法的对象,下文将详细说明。
当 CustomScan 扫描单个关系时,
scan.scanrelid 必须是要扫描的表的范围表索引。当它替代一个连接时,
scan.scanrelid 应为零。
计划树必须能用 copyObject 复制,因此存储在
“custom” 字段中的所有数据都必须由该函数能处理的节点构成。此外,自定义扫描提供者不能把
CustomScan 嵌入一个更大的结构来替代该结构本身,而
CustomPath 或
CustomScanState 是可以这样做的。
Node *(*CreateCustomScanState) (CustomScan *cscan);
为该 CustomScan 分配一个
CustomScanState。实际分配往往比普通
CustomScanState 所需的更大,因为许多提供者会希望把它作为更大结构的第一个字段嵌入。返回的值必须正确设置节点标记与
methods,但其他字段在此阶段应保持为零;在
ExecInitCustomScan 完成基本初始化之后,会调用
BeginCustomScan 回调,给自定义扫描提供者一个机会去做其他任何需要的事情。