Postgresql 中文操作指南
61.2. Creating Custom Scan Plans #
定制扫描在完成的计划树中使用以下结构表示:
A custom scan is represented in a finished plan tree using the following structure:
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 必须指向一个(通常是静态分配的)对象,该对象实现所需的自定义扫描方法,这些方法将在下面进一步详细介绍。
scan must be initialized as for any other scan, including estimated costs, target lists, qualifications, and so on. flags is a bit mask with the same meaning as in CustomPath. custom_plans can be used to store child Plan nodes. custom_exprs should be used to store expression trees that will need to be fixed up by setrefs.c and subselect.c, while custom_private should be used to store other private data that is only used by the custom scan provider itself. custom_scan_tlist can be NIL when scanning a base relation, indicating that the custom scan returns scan tuples that match the base relation’s row type. Otherwise it is a target list describing the actual scan tuples. custom_scan_tlist must be provided for joins, and could be provided for scans if the custom scan provider can compute some non-Var expressions. custom_relids is set by the core code to the set of relations (range table indexes) that this scan node handles; except when this scan is replacing a join, it will have only one member. methods must point to a (usually statically allocated) object implementing the required custom scan methods, which are further detailed below.
当 CustomScan 扫描单个关系时,scan.scanrelid 必须是要扫描的表的范围表索引。当它替换联接时,scan.scanrelid 应为零。
When a CustomScan scans a single relation, scan.scanrelid must be the range table index of the table to be scanned. When it replaces a join, scan.scanrelid should be zero.
计划树必须能够使用 copyObject 复制,因此存储在“自定义”字段中的所有数据都必须由该函数可以处理的节点组成。此外,自定义扫描提供程序不能为结构本身替换一个包含 CustomScan 的更大的结构,而对于 CustomPath 或 CustomScanState 来说是可能的。
Plan trees must be able to be duplicated using copyObject, so all the data stored within the “custom” fields must consist of nodes that that function can handle. Furthermore, custom scan providers cannot substitute a larger structure that embeds a CustomScan for the structure itself, as would be possible for a CustomPath or CustomScanState.
61.2.1. Custom Scan Plan Callbacks #
Node *(*CreateCustomScanState) (CustomScan *cscan);
为此 CustomScan 分配一个 CustomScanState。实际分配通常会比普通 CustomScanState 所需的更大,因为许多提供程序希望将其嵌入到更大结构的第一个字段中。返回的值必须有适当设置的节点标记和 methods,但其他字段在此阶段应保留为零;在 ExecInitCustomScan 执行基本初始化之后,将调用 BeginCustomScan 回调以向自定义扫描提供程序提供一个机会,让它完成任何其他需要的事情。
Allocate a CustomScanState for this CustomScan. The actual allocation will often be larger than required for an ordinary CustomScanState, because many providers will wish to embed that as the first field of a larger structure. The value returned must have the node tag and methods set appropriately, but other fields should be left as zeroes at this stage; after ExecInitCustomScan performs basic initialization, the BeginCustomScan callback will be invoked to give the custom scan provider a chance to do whatever else is needed.