56.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
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.
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.
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
.
56.2.1. Custom Scan Plan Callbacks
Node *(*CreateCustomScanState) (CustomScan *cscan);
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.
void (*TextOutCustomScan) (StringInfo str, const CustomScan *node);
Generate additional output when nodeToString
is invoked on this custom plan node. This callback is optional. Since nodeToString
will automatically dump all fields in the structure, including the substructure of the “custom” fields, there is usually not much need for this callback.