61.2. 创建自定义扫描计划#
自定义扫描在已完成的计划树中使用以下结构表示
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
则可以。
61.2.1. 自定义扫描计划回调#
Node *(*CreateCustomScanState) (CustomScan *cscan);
为该CustomScan
分配一个CustomScanState
。实际分配通常会比普通CustomScanState
所需的大,因为许多提供者希望将它嵌入为更大结构的第一个字段。返回的值必须具有适当设置的节点标记和methods
,但其他字段在此阶段应保留为零;在ExecInitCustomScan
执行基本初始化后,将调用BeginCustomScan
回调,以便为自定义扫描提供者提供机会来执行其他任何所需的操作。