## Chapter 59. Writing A Custom Scan Provider

PostgreSQL supports a set of experimental facilities which are intended to allow extension modules to add new scan types to the system. Unlike a foreign data wrapper, which is only responsible for knowing how to scan its own foreign tables, a custom scan provider can provide an alternative method of scanning any relation in the system. Typically, the motivation for writing a custom scan provider will be to allow the use of some optimization not supported by the core system, such as caching or some form of hardware acceleration. This chapter outlines how to write a new custom scan provider.

Implementing a new type of custom scan is a three-step process. First, during planning, it is necessary to generate access paths representing a scan using the proposed strategy. Second, if one of those access paths is selected by the planner as the optimal strategy for scanning a particular relation, the access path must be converted to a plan. Finally, it must be possible to execute the plan and generate the same results that would have been generated for any other access path targeting the same relation.

## 59.1. Creating Custom Scan Paths

A custom scan provider will typically add paths for a base relation by setting the following hook, which is called after the core code has generated what it believes to be the complete and correct set of access paths for the relation.

    typedef void (*set_rel_pathlist_hook_type) (PlannerInfo *root,
                                                RelOptInfo *rel,
                                                Index rti,
                                                RangeTblEntry *rte);
    extern PGDLLIMPORT set_rel_pathlist_hook_type set_rel_pathlist_hook;

Although this hook function can be used to examine, modify, or remove paths generated by the core system, a custom scan provider will typically confine itself to generating `CustomPath` objects and adding them to `rel` using `add_path`. The custom scan provider is responsible for initializing the `CustomPath` object, which is declared like this:

    typedef struct CustomPath
    {
        Path      path;
        uint32    flags;
        List     *custom_paths;
        List     *custom_private;
        const CustomPathMethods *methods;
    } CustomPath;

`path` must be initialized as for any other path, including the row-count estimate, start and total cost, and sort ordering provided by this path. `flags` is a bit mask, which should include `CUSTOMPATH_SUPPORT_BACKWARD_SCAN` if the custom path can support a backward scan and `CUSTOMPATH_SUPPORT_MARK_RESTORE` if it can support mark and restore. Both capabilities are optional. An optional `custom_paths` is a list of `Path` nodes used by this custom-path node; these will be transformed into `Plan` nodes by planner. `custom_private` can be used to store the custom path's private data. Private data should be stored in a form that can be handled by `nodeToString`, so that debugging routines that attempt to print the custom path will work as designed. `methods` must point to a (usually statically allocated) object implementing the required custom path methods, of which there is currently only one. The `LibraryName` and `SymbolName` fields must also be initialized so that the dynamic loader can resolve them to locate the method table.

A custom scan provider can also provide join paths. Just as for base relations, such a path must produce the same output as would normally be produced by the join it replaces. To do this, the join provider should set the following hook, and then within the hook function, create `CustomPath` path(s) for the join relation.

    typedef void (*set_join_pathlist_hook_type) (PlannerInfo *root,
                                                 RelOptInfo *joinrel,
                                                 RelOptInfo *outerrel,
                                                 RelOptInfo *innerrel,
                                                 JoinType jointype,
                                                 JoinPathExtraData *extra);
    extern PGDLLIMPORT set_join_pathlist_hook_type set_join_pathlist_hook;

This hook will be invoked repeatedly for the same join relation, with different combinations of inner and outer relations; it is the responsibility of the hook to minimize duplicated work.

### 59.1.1. Custom Scan Path Callbacks

    Plan *(*PlanCustomPath) (PlannerInfo *root,
                             RelOptInfo *rel,
                             CustomPath *best_path,
                             List *tlist,
                             List *clauses,
                             List *custom_plans);

Convert a custom path to a finished plan. The return value will generally be a `CustomScan` object, which the callback must allocate and initialize. See Section 59.2 for more details.