60.1. Creación de rutas de escaneo personalizadas #

60.1.1. Callbacks de ruta de escaneo personalizada

Un proveedor de escaneo personalizado agregará típicamente rutas para una relación base estableciendo el siguiente hook (gancho), que se llama después de que el código central ha generado todas las rutas de acceso posibles para la relación (excepto las rutas Gather y Gather Merge, que se realizan después de esta llamada para que puedan usar rutas parciales agregadas por el hook):

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;

Aunque esta función de hook se puede usar para examinar, modificar o eliminar rutas generadas por el sistema central, un proveedor de escaneo personalizado típicamente se limitará a generar objetos CustomPath y agregarlos a rel usando add_path, o add_partial_path si son rutas parciales. El proveedor de escaneo personalizado es responsable de inicializar el objeto CustomPath, que se declara así:

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

path debe inicializarse como para cualquier otra ruta, incluyendo la estimación del número de filas, el costo inicial y total, y el ordenamiento proporcionado por esta ruta. flags es una máscara de bits que especifica si el proveedor de escaneo puede admitir ciertas capacidades opcionales. flags debe incluir CUSTOMPATH_SUPPORT_BACKWARD_SCAN si la ruta personalizada admite un escaneo hacia atrás, CUSTOMPATH_SUPPORT_MARK_RESTORE si admite marcar y restaurar, y CUSTOMPATH_SUPPORT_PROJECTION si puede realizar proyecciones. (Si CUSTOMPATH_SUPPORT_PROJECTION no está establecido, al nodo de escaneo solo se le pedirá que produzca Vars de la relación escaneada; mientras que si se establece ese flag, el nodo de escaneo debe ser capaz de evaluar expresiones escalares sobre estas Vars). Un campo opcional custom_paths es una lista de nodos Path utilizados por este nodo de ruta personalizada; el planificador los transformará en nodos Plan. Como se describe a continuación, también se pueden crear rutas personalizadas para relaciones de unión (join). En tal caso, se debe usar custom_restrictinfo para almacenar el conjunto de cláusulas de unión a aplicar a la unión que la ruta personalizada reemplaza. De lo contrario, debe ser NIL. custom_private se puede utilizar para almacenar los datos privados de la ruta personalizada. Los datos privados deben almacenarse en una forma que pueda ser manejada por nodeToString, para que las rutinas de depuración que intentan imprimir la ruta personalizada funcionen como se diseñó. methods debe apuntar a un objeto (generalmente asignado estáticamente) que implemente los métodos de ruta personalizados requeridos, que se detallan más adelante.

Un proveedor de escaneo personalizado también puede proporcionar rutas de unión. Al igual que para las relaciones base, dicha ruta debe producir la misma salida que normalmente se produciría por la unión que reemplaza. Para hacer esto, el proveedor de unión debe establecer el siguiente hook, y luego dentro de la función del hook, crear ruta(s) CustomPath para la relación de unión.

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;

Este hook se invocará repetidamente para la misma relación de unión, con diferentes combinaciones de relaciones internas y externas; es responsabilidad del hook minimizar el trabajo duplicado.

Ten en cuenta también que el conjunto de cláusulas de unión a aplicar a la unión, que se pasa como extra->restrictlist, varía según la combinación de relaciones internas y externas. Una ruta CustomPath generada para el joinrel debe contener el conjunto de cláusulas de unión que utiliza, que el planificador usará para convertir la ruta CustomPath en un plan, si el planificador la selecciona como la mejor ruta para el joinrel.

60.1.1. Callbacks de ruta de escaneo personalizada #

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

Convierte una ruta personalizada en un plan terminado. El valor de retorno generalmente será un objeto CustomScan, que el callback debe asignar e inicializar. Consulta la Section 60.2 para obtener más detalles.

List *(*ReparameterizeCustomPathByChild) (PlannerInfo *root,
                                          List *custom_private,
                                          RelOptInfo *child_rel);

Este callback se llama al convertir una ruta parametrizada por el padre más alto de la relación hija dada child_rel para ser parametrizada por la relación hija. El callback se usa para volver a parametrizar cualquier ruta o traducir cualquier nodo de expresión guardado en el miembro custom_private dado de un CustomPath. El callback puede usar reparameterize_path_by_child, adjust_appendrel_attrs o adjust_appendrel_attrs_multilevel según sea necesario.