58.2. Rutinas de retrollamada del adaptador de datos externos #

58.2.1. Rutinas de FDW para el escaneo de tablas externas
58.2.2. Rutinas de FDW para el escaneo de uniones externas
58.2.3. Rutinas de FDW para la planificación del procesamiento posterior al escaneo/unión
58.2.4. Rutinas de FDW para actualizar tablas externas
58.2.5. Rutinas de FDW para TRUNCATE
58.2.6. Rutinas de FDW para el bloqueo de filas
58.2.7. Rutinas de FDW para EXPLAIN
58.2.8. Rutinas de FDW para ANALYZE
58.2.9. Rutinas de FDW para IMPORT FOREIGN SCHEMA
58.2.10. Rutinas de FDW para ejecución paralela
58.2.11. Rutinas de FDW para ejecución asíncrona
58.2.12. Rutinas de FDW para la parametrización de rutas

La función de manejo del FDW devuelve una estructura FdwRoutine asignada con palloc que contiene punteros a las funciones de retrollamada descritas a continuación. Las funciones relacionadas con el escaneo son obligatorias, el resto son opcionales.

El tipo de estructura FdwRoutine se declara en src/include/foreign/fdwapi.h, el cual puedes consultar para obtener detalles adicionales.

58.2.1. Rutinas de FDW para el escaneo de tablas externas #

void
GetForeignRelSize(PlannerInfo *root,
                  RelOptInfo *baserel,
                  Oid foreigntableid);

Obtiene estimaciones del tamaño de la relación para una tabla externa. Se llama al comienzo de la planificación de una consulta que escanea una tabla externa. root es la información global del planificador sobre la consulta; baserel es la información del planificador sobre esta tabla; y foreigntableid es el OID de pg_class de la tabla externa. (foreigntableid podría obtenerse de las estructuras de datos del planificador, pero se pasa explícitamente para ahorrar esfuerzo).

Esta función debe actualizar baserel->rows para que sea el número esperado de filas devueltas por el escaneo de la tabla, después de tener en cuenta el filtrado realizado por las condiciones de restricción (restriction quals). El valor inicial de baserel->rows es solo una estimación constante por defecto, la cual debe ser reemplazada si es posible. La función también puede optar por actualizar baserel->width si puede calcular una mejor estimación del ancho promedio de las filas de resultado. (El valor inicial se basa en los tipos de datos de las columnas y en los valores de ancho promedio de columna medidos por el último ANALYZE). Además, esta función puede actualizar baserel->tuples si puede calcular una mejor estimación del número total de filas de la tabla externa. (El valor inicial proviene de pg_class.reltuples, que representa el número total de filas visto por el último ANALYZE; será -1 si no se ha realizado ningún ANALYZE en esta tabla externa).

Consulta la Section 58.4 para obtener información adicional.

void
GetForeignPaths(PlannerInfo *root,
                RelOptInfo *baserel,
                Oid foreigntableid);

Crea posibles rutas de acceso (access paths) para un escaneo en una tabla externa. Se llama durante la planificación de la consulta. Los parámetros son los mismos que para GetForeignRelSize, la cual ya ha sido llamada.

Esta función debe generar al menos una ruta de acceso (nodo ForeignPath) para un escaneo en la tabla externa y debe llamar a add_path para añadir cada una de esas rutas a baserel->pathlist. Se recomienda usar create_foreignscan_path para construir los nodos ForeignPath. La función puede generar múltiples rutas de acceso, por ejemplo, una ruta que tenga pathkeys válidos para representar un resultado preordenado. Cada ruta de acceso debe contener estimaciones de costo, y puede contener cualquier información privada de FDW que sea necesaria para identificar el método de escaneo específico previsto.

Consulta la Section 58.4 para obtener información adicional.

ForeignScan *
GetForeignPlan(PlannerInfo *root,
               RelOptInfo *baserel,
               Oid foreigntableid,
               ForeignPath *best_path,
               List *tlist,
               List *scan_clauses,
               Plan *outer_plan);

Crea un nodo de plan ForeignScan a partir de la ruta de acceso externa seleccionada. Se llama al final de la planificación de la consulta. Los parámetros son como para GetForeignRelSize, más la ruta ForeignPath seleccionada (producida previamente por GetForeignPaths, GetForeignJoinPaths o GetForeignUpperPaths), la lista de objetivos (target list) a emitir por el nodo de plan, las cláusulas de restricción a imponer por el nodo de plan, y el subplan externo de ForeignScan, el cual se utiliza para las recomprobaciones realizadas por RecheckForeignScan. (Si la ruta es para una unión (join) en lugar de una relación base, foreigntableid es InvalidOid).

Esta función debe crear y devolver un nodo de plan ForeignScan; se recomienda usar make_foreignscan para construir el nodo ForeignScan.

Consulta la Section 58.4 para obtener información adicional.

void
BeginForeignScan(ForeignScanState *node,
                 int eflags);

Comienza a ejecutar un escaneo externo. Se llama durante el inicio del ejecutor. Debe realizar cualquier inicialización necesaria antes de que pueda comenzar el escaneo, pero no comenzar a ejecutar el escaneo real (eso debe hacerse en la primera llamada a IterateForeignScan). El nodo ForeignScanState ya ha sido creado, pero su campo fdw_state sigue siendo NULL. La información sobre la tabla a escanear es accesible a través del nodo ForeignScanState (en particular, desde el nodo de plan ForeignScan subyacente, que contiene cualquier información privada de FDW proporcionada por GetForeignPlan). eflags contiene bits de banderas que describen el modo de funcionamiento del ejecutor para este nodo de plan.

Ten en cuenta que cuando (eflags & EXEC_FLAG_EXPLAIN_ONLY) es verdadero, esta función no debe realizar ninguna acción externamente visible; solo debe hacer lo mínimo requerido para que el estado del nodo sea válido para ExplainForeignScan y EndForeignScan.

TupleTableSlot *
IterateForeignScan(ForeignScanState *node);

Obtiene una fila de la fuente externa, devolviéndola en una ranura de tabla de tuplas (se debe usar la ranura ScanTupleSlot del nodo para este propósito). Devuelve NULL si no hay más filas disponibles. La infraestructura de ranuras de tablas de tuplas permite devolver una tupla física o virtual; en la mayoría de los casos, la última opción es preferible desde una perspectiva de rendimiento. Ten en cuenta que esto se llama en un contexto de memoria de corta duración que se restablecerá entre invocaciones. Crea un contexto de memoria en BeginForeignScan si necesitas un almacenamiento de mayor duración, o usa el es_query_cxt del EState del nodo.

Las filas devueltas deben coincidir con la lista de objetivos fdw_scan_tlist si se proporcionó una, de lo contrario deben coincidir con el tipo de fila de la tabla externa que se está escaneando. Si decides optimizar omitiendo la obtención de columnas que no son necesarias, debes insertar nulos en esas posiciones de columna, o bien generar una lista fdw_scan_tlist con esas columnas omitidas.

Ten en cuenta que al ejecutor de PostgreSQL no le importa si las filas devueltas violan alguna restricción que se haya definido en la tabla externa — pero al planificador sí le importa, y puede optimizar incorrectamente las consultas si hay filas visibles en la tabla externa que no satisfacen una restricción declarada. Si se viola una restricción cuando el usuario ha declarado que la restricción debe cumplirse, puede ser apropiado generar un error (tal como tendrías que hacer en el caso de una discrepancia de tipos de datos).

void
ReScanForeignScan(ForeignScanState *node);

Reinicia el escaneo desde el principio. Ten en cuenta que cualquier parámetro del que dependa el escaneo puede haber cambiado de valor, por lo que el nuevo escaneo no necesariamente devolverá exactamente las mismas filas.

void
EndForeignScan(ForeignScanState *node);

Finaliza el escaneo y libera los recursos. Normalmente no es importante liberar la memoria asignada con palloc, pero por ejemplo, se deben cerrar los archivos abiertos y las conexiones a servidores remotos.

58.2.2. Rutinas de FDW para el escaneo de uniones externas #

Si un FDW admite la realización de uniones externas de forma remota (en lugar de obtener los datos de ambas tablas y realizar la unión localmente), debe proporcionar esta función de retrollamada:

void
GetForeignJoinPaths(PlannerInfo *root,
                    RelOptInfo *joinrel,
                    RelOptInfo *outerrel,
                    RelOptInfo *innerrel,
                    JoinType jointype,
                    JoinPathExtraData *extra);

Crea posibles rutas de acceso para una unión de dos (o más) tablas externas que pertenecen todas al mismo servidor externo. Esta función opcional se llama durante la planificación de la consulta. Al igual que con GetForeignPaths, esta función debe generar ruta(s) ForeignPath para la joinrel proporcionada (usa create_foreign_join_path para construirlas), y llamar a add_path para añadir estas rutas al conjunto de rutas consideradas para la unión. Pero a diferencia de GetForeignPaths, no es necesario que esta función tenga éxito en la creación de al menos una ruta, ya que las rutas que involucran uniones locales siempre son posibles.

Ten en cuenta que esta función se invocará repetidamente para la misma relación de unión, con diferentes combinaciones de relaciones internas y externas; es responsabilidad del FDW 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 ForeignPath generada para la joinrel debe contener el conjunto de cláusulas de unión que utiliza, que el planificador usará para convertir la ruta ForeignPath en un plan, si el planificador la selecciona como la mejor ruta para la joinrel.

Si se elige una ruta ForeignPath para la unión, esta representará todo el proceso de unión; las rutas generadas para las tablas componentes y las uniones subsidiarias no se utilizarán. El procesamiento posterior de la ruta de unión procede de manera muy similar a como lo hace para una ruta que escanea una sola tabla externa. Una diferencia es que el campo scanrelid del nodo de plan ForeignScan resultante debe establecerse en cero, ya que no hay una sola relación que represente; en su lugar, el campo fs_relids del nodo ForeignScan representa el conjunto de relaciones que se unieron. (Este último campo se configura automáticamente por el código del planificador principal y no necesita ser completado por el FDW). Otra diferencia es que, debido a que la lista de columnas para una unión remota no se puede encontrar en los catálogos del sistema, el FDW debe completar fdw_scan_tlist con una lista adecuada de nodos TargetEntry, que representen el conjunto de columnas que suministrará en tiempo de ejecución en las tuplas que devuelva.

Note

A partir de PostgreSQL 16, fs_relids incluye los índices de la tabla de rango (rangetable indexes) de las uniones externas, si alguna estuvo involucrada en esta unión. El nuevo campo fs_base_relids incluye solo índices de relación base y, por lo tanto, imita la antigua semántica de fs_relids.

Consulta la Section 58.4 para obtener información adicional.

58.2.3. Rutinas de FDW para la planificación del procesamiento posterior al escaneo/unión #

Si un FDW admite la realización de un procesamiento remoto posterior al escaneo/unión, como la agregación remota, debe proporcionar esta función de retrollamada:

void
GetForeignUpperPaths(PlannerInfo *root,
                     UpperRelationKind stage,
                     RelOptInfo *input_rel,
                     RelOptInfo *output_rel,
                     void *extra);

Crea posibles rutas de acceso para el procesamiento de la relación superior (upper relation), que es el término del planificador para todo el procesamiento de consultas posterior al escaneo/unión, como agregaciones, funciones de ventana, ordenamiento y actualizaciones de tablas. Esta función opcional se llama durante la planificación de la consulta. Actualmente, se llama solo si todas las relaciones base involucradas en la consulta pertenecen al mismo FDW. Esta función debe generar ruta(s) ForeignPath para cualquier procesamiento posterior al escaneo/unión que el FDW sepa cómo realizar de forma remota (usa create_foreign_upper_path para construirlas), y llamar a add_path para añadir estas rutas a la relación superior indicada. Al igual que con GetForeignJoinPaths, no es necesario que esta función tenga éxito en la creación de ninguna ruta, ya que las rutas que involucran procesamiento local siempre son posibles.

El parámetro stage identifica qué paso posterior al escaneo/unión se está considerando actualmente. output_rel es la relación superior que debe recibir las rutas que representan la computación de este paso, e input_rel es la relación que representa la entrada a este paso. El parámetro extra proporciona detalles adicionales, actualmente, se establece solo para UPPERREL_PARTIAL_GROUP_AGG o UPPERREL_GROUP_AGG, en cuyo caso apunta a una estructura GroupPathExtraData; o para UPPERREL_FINAL, en cuyo caso apunta a una estructura FinalPathExtraData. (Ten en cuenta que las rutas ForeignPath añadidas a output_rel normalmente no tendrían ninguna dependencia directa en las rutas de input_rel, ya que se espera que su procesamiento se realice externamente. Sin embargo, examinar las rutas generadas previamente para el paso de procesamiento anterior puede ser útil para evitar trabajo de planificación redundante).

Consulta la Section 58.4 para obtener información adicional.

58.2.4. Rutinas de FDW para actualizar tablas externas #

Si un FDW admite tablas externas de escritura, debe proporcionar algunas o todas las siguientes funciones de retrollamada, según las necesidades y capacidades del FDW:

void
AddForeignUpdateTargets(PlannerInfo *root,
                        Index rtindex,
                        RangeTblEntry *target_rte,
                        Relation target_relation);

Las operaciones UPDATE y DELETE se realizan contra filas previamente obtenidas por las funciones de escaneo de tablas. El FDW puede necesitar información adicional, como un ID de fila o los valores de las columnas de clave primaria, para garantizar que pueda identificar la fila exacta a actualizar o eliminar. Para dar soporte a eso, esta función puede añadir columnas de destino ocultas adicionales, o junk (basura), a la lista de columnas que se recuperarán de la tabla externa durante un UPDATE o DELETE.

Para hacer eso, construye un Var que represente el valor adicional que necesitas y pásalo a add_row_identity_var, junto con un nombre para la columna junk. (Puedes hacer esto más de una vez si se necesitan varias columnas). Debes elegir un nombre de columna junk distinto para cada Var diferente que necesites, excepto que las variables Var que son idénticas excepto por el campo varno pueden y deben compartir el nombre de columna. El sistema principal utiliza los nombres de columna junk tableoid para la columna tableoid de una tabla, ctid o ctidN para ctid, wholerow para una variable Var de fila completa marcada con vartype = RECORD, y wholerowN para una variable Var de fila completa con vartype igual al tipo de fila declarado de la tabla. Reutiliza estos nombres cuando puedas (el planificador combinará solicitudes duplicadas de columnas junk idénticas). Si necesitas otro tipo de columna junk además de estas, sería aconsejable elegir un nombre con el prefijo del nombre de tu extensión para evitar conflictos con otros FDW.

Si el puntero AddForeignUpdateTargets se establece en NULL, no se añaden expresiones de destino adicionales. (Esto imposibilitará la implementación de operaciones DELETE, aunque UPDATE aún puede ser factible si el FDW confía en una clave primaria inalterable para identificar las filas).

List *
PlanForeignModify(PlannerInfo *root,
                  ModifyTable *plan,
                  Index resultRelation,
                  int subplan_index);

Realiza cualquier acción de planificación adicional necesaria para una inserción, actualización o eliminación en una tabla externa. Esta función genera la información privada de FDW que se adjuntará al nodo de plan ModifyTable que realiza la acción de actualización. Esta información privada debe tener la forma de una lista List, y se entregará a BeginForeignModify durante la etapa de ejecución.

root is la información global del planificador sobre la consulta. plan es el nodo de plan ModifyTable, que está completo excepto por el campo fdwPrivLists. resultRelation identifica la tabla externa de destino mediante su índice de tabla de rango (range table index). subplan_index identifica qué destino del nodo de plan ModifyTable es este, contando desde cero; usa esto si deseas indexar en las subestructuras por relación de destino del nodo de plan.

Consulta la Section 58.4 para obtener información adicional.

Si el puntero PlanForeignModify se establece en NULL, no se realizan acciones adicionales en tiempo de planificación, y la lista fdw_private entregada a BeginForeignModify será NIL.

void
BeginForeignModify(ModifyTableState *mtstate,
                   ResultRelInfo *rinfo,
                   List *fdw_private,
                   int subplan_index,
                   int eflags);

Comienza a ejecutar una operación de modificación de tabla externa. Esta rutina se llama durante el inicio del ejecutor. Debe realizar cualquier inicialización necesaria antes de las modificaciones reales de la tabla. Posteriormente, se llamará a ExecForeignInsert/ExecForeignBatchInsert, ExecForeignUpdate o ExecForeignDelete para la(s) tupla(s) a insertar, actualizar o eliminar.

mtstate es el estado general del nodo de plan ModifyTable que se está ejecutando; los datos globales sobre el plan y el estado de ejecución están disponibles a través de esta estructura. rinfo es la estructura ResultRelInfo que describe la tabla externa de destino. (El campo ri_FdwState de ResultRelInfo está disponible para que el FDW almacene cualquier estado privado que necesite para esta operación). fdw_private contiene los datos privados generados por PlanForeignModify, si los hay. subplan_index identifica qué destino del nodo de plan ModifyTable es este. eflags contiene bits de banderas que describen el modo de funcionamiento del ejecutor para este nodo de plan.

Ten en cuenta que cuando (eflags & EXEC_FLAG_EXPLAIN_ONLY) es verdadero, esta función no debe realizar ninguna acción externamente visible; solo debe hacer lo mínimo requerido para que el estado del nodo sea válido para ExplainForeignModify y EndForeignModify.

Si el puntero BeginForeignModify se establece en NULL, no se realiza ninguna acción durante el inicio del ejecutor.

TupleTableSlot *
ExecForeignInsert(EState *estate,
                  ResultRelInfo *rinfo,
                  TupleTableSlot *slot,
                  TupleTableSlot *planSlot);

Inserta una tupla en la tabla externa. estate es el estado de ejecución global para la consulta. rinfo es la estructura ResultRelInfo que describe la tabla externa de destino. slot contiene la tupla a insertar; coincidirá con la definición del tipo de fila de la tabla externa. planSlot contiene la tupla generada por el subplan del nodo de plan ModifyTable; difiere de slot en que posiblemente contiene columnas junk adicionales. (El planSlot suele ser de poco interés para los casos de INSERT, pero se proporciona para completar la interfaz).

El valor de retorno es una ranura que contiene los datos que realmente se insertaron (esto podría diferir de los datos suministrados, por ejemplo, como resultado de las acciones de los disparadores), o NULL si no se insertó ninguna fila realmente (nuevamente, típicamente como resultado de los disparadores). La ranura slot pasada se puede reutilizar para este propósito.

Los datos en la ranura devuelta se usan solo si la sentencia INSERT tiene una cláusula RETURNING o involucra una vista WITH CHECK OPTION; o si la tabla externa tiene un disparador AFTER ROW. Los disparadores requieren todas las columnas, pero el FDW podría optar por optimizar omitiendo la devolución de algunas o todas las columnas según el contenido de la cláusula RETURNING o las restricciones de WITH CHECK OPTION. De todos modos, se debe devolver alguna ranura para indicar el éxito, o de lo contrario el recuento de filas reportado por la consulta será incorrecto.

Si el puntero ExecForeignInsert se establece en NULL, los intentos de insertar en la tabla externa fallarán con un mensaje de error.

Ten en cuenta que esta función también se llama cuando se insertan tuplas enrutadas en una partición de tabla externa o al ejecutar COPY FROM en una tabla externa, en cuyo caso se llama de una manera diferente a la del caso de INSERT. Consulta las funciones de retrollamada descritas a continuación que permiten al FDW dar soporte a eso.

TupleTableSlot **
ExecForeignBatchInsert(EState *estate,
                       ResultRelInfo *rinfo,
                       TupleTableSlot **slots,
                       TupleTableSlot **planSlots,
                       int *numSlots);

Inserta múltiples tuplas en lote (bulk) en la tabla externa. Los parámetros son los mismos que para ExecForeignInsert excepto que slots y planSlots contienen múltiples tuplas y *numSlots especifica el número de tuplas en esos arrays.

El valor de retorno es un array de ranuras que contienen los datos que realmente se insertaron (esto podría diferir de los datos suministrados, por ejemplo, como resultado de las acciones de los disparadores). Las ranuras slots pasadas se pueden reutilizar para este propósito. El número de tuplas insertadas con éxito se devuelve en *numSlots.

Los datos en la ranura devuelta se usan solo si la sentencia INSERT involucra una vista WITH CHECK OPTION; o si la tabla externa tiene un disparador AFTER ROW. Los disparadores requieren todas las columnas, pero el FDW podría optar por optimizar omitiendo la devolución de algunas o todas las columnas según el contenido de las restricciones de WITH CHECK OPTION.

Si el puntero ExecForeignBatchInsert o GetForeignModifyBatchSize se establece en NULL, los intentos de insertar en la tabla externa utilizarán ExecForeignInsert. Esta función no se utiliza si el INSERT tiene la cláusula RETURNING.

Ten en cuenta que esta función también se llama cuando se insertan tuplas enrutadas en una partición de tabla externa o al ejecutar COPY FROM en una tabla externa, en cuyo caso se llama de una manera diferente a la del caso de INSERT. Consulta las funciones de retrollamada descritas a continuación que permiten al FDW dar soporte a eso.

int
GetForeignModifyBatchSize(ResultRelInfo *rinfo);

Reporta el número máximo de tuplas que una sola llamada a ExecForeignBatchInsert puede manejar para la tabla externa especificada. El ejecutor pasa como máximo el número dado de tuplas a ExecForeignBatchInsert. rinfo es la estructura ResultRelInfo que describe la tabla externa de destino. Se espera que el FDW proporcione una opción de servidor externo y/o tabla externa para que el usuario configure este valor, o bien algún valor codificado en duro (hard-coded).

Si el puntero ExecForeignBatchInsert o GetForeignModifyBatchSize se establece en NULL, los intentos de insertar en la tabla externa utilizarán ExecForeignInsert.

TupleTableSlot *
ExecForeignUpdate(EState *estate,
                  ResultRelInfo *rinfo,
                  TupleTableSlot *slot,
                  TupleTableSlot *planSlot);

Actualiza una tupla en la tabla externa. estate es el estado de ejecución global para la consulta. rinfo es la estructura ResultRelInfo que describe la tabla externa de destino. slot contiene los nuevos datos para la tupla; coincidirá con la definición del tipo de fila de la tabla externa. planSlot contiene la tupla generada por el subplan del nodo de plan ModifyTable. A diferencia de slot, esta tupla contiene solo los nuevos valores para las columnas cambiadas por la consulta, así que no confíes en los números de atributo de la tabla externa para indexar en planSlot. Además, planSlot suele contener columnas junk adicionales. In particular, cualquier columna junk que haya sido solicitada por AddForeignUpdateTargets estará disponible en esta ranura.

El valor de retorno es una ranura que contiene la fila tal como fue realmente actualizada (esto podría diferir de los datos suministrados, por ejemplo, como resultado de las acciones de los disparadores), o NULL si no se actualizó ninguna fila realmente (nuevamente, típicamente como resultado de los disparadores). La ranura slot pasada se puede reutilizar para este propósito.

Los datos en la ranura devuelta se usan solo si la sentencia UPDATE tiene una cláusula RETURNING o involucra una vista WITH CHECK OPTION; o si la tabla externa tiene un disparador AFTER ROW. Los disparadores requieren todas las columnas, pero el FDW podría optar por optimizar omitiendo la devolución de algunas o todas las columnas según el contenido de la cláusula RETURNING o las restricciones de WITH CHECK OPTION. De todos modos, se debe devolver alguna ranura para indicar el éxito, o de lo contrario el recuento de filas reportado por la consulta será incorrecto.

Si el puntero ExecForeignUpdate se establece en NULL, los intentos de actualizar la tabla externa fallarán con un mensaje de error.

TupleTableSlot *
ExecForeignDelete(EState *estate,
                  ResultRelInfo *rinfo,
                  TupleTableSlot *slot,
                  TupleTableSlot *planSlot);

Elimina una tupla de la tabla externa. estate es el estado de ejecución global para la consulta. rinfo es la estructura ResultRelInfo que describe la tabla externa de destino. slot no contiene nada útil al ser llamada, pero se puede usar para contener la tupla devuelta. planSlot contiene la tupla generada por el subplan del nodo de plan ModifyTable; en particular, llevará cualquier columna junk que haya sido solicitada por AddForeignUpdateTargets. Las columnas junk deben usarse para identificar la tupla a eliminar.

El valor de retorno es una ranura que contiene la fila que fue eliminada, o NULL si no se eliminó ninguna fila (típicamente como resultado de los disparadores). La ranura slot pasada se puede usar para contener la tupla a devolver.

Los datos en la ranura devuelta se usan solo si la consulta DELETE tiene una cláusula RETURNING o la tabla externa tiene un disparador AFTER ROW. Los disparadores requieren todas las columnas, pero el FDW podría optar por optimizar omitiendo la devolución de algunas o todas las columnas según el contenido de la cláusula RETURNING. De todos modos, se debe devolver alguna ranura para indicar el éxito, o de lo contrario el recuento de filas reportado por la consulta será incorrecto.

Si el puntero ExecForeignDelete se establece en NULL, los intentos de eliminar de la tabla externa fallarán con un mensaje de error.

void
EndForeignModify(EState *estate,
                 ResultRelInfo *rinfo);

Finaliza la actualización de la tabla y libera los recursos. Normalmente no es importante liberar la memoria asignada con palloc, pero por ejemplo, se deben cerrar los archivos abiertos y las conexiones a servidores remotos.

Si el puntero EndForeignModify se establece en NULL, no se realiza ninguna acción durante el cierre del ejecutor.

Las tuplas insertadas en una tabla particionada mediante INSERT o COPY FROM se enrutan a las particiones. Si un FDW admite particiones de tabla externa enrutables, también debe proporcionar las siguientes funciones de retrollamada. Estas funciones también se llaman cuando se ejecuta COPY FROM en una tabla externa.

void
BeginForeignInsert(ModifyTableState *mtstate,
                   ResultRelInfo *rinfo);

Comienza a ejecutar una operación de inserción en una tabla externa. Esta rutina se llama justo antes de que se inserte la primera tupla en la tabla externa en ambos casos: cuando es la partición elegida para el enrutamiento de tuplas y cuando es el destino especificado en un comando COPY FROM. Debe realizar cualquier inicialización necesaria antes de la inserción real. Posteriormente, se llamará a ExecForeignInsert o ExecForeignBatchInsert para la(s) tupla(s) a insertar en la tabla externa.

mtstate es el estado general del nodo de plan ModifyTable que se está ejecutando; los datos globales sobre el plan y el estado de ejecución están disponibles a través de esta estructura. rinfo es la estructura ResultRelInfo que describe la tabla externa de destino. (El campo ri_FdwState de ResultRelInfo está disponible para que el FDW almacene cualquier estado privado que necesite para esta operación).

Cuando esto es llamado por un comando COPY FROM, no se proporcionan los datos globales relacionados con el plan en mtstate y el parámetro planSlot de ExecForeignInsert llamado posteriormente para cada tupla insertada es NULL, ya sea que la tabla externa sea la partición elegida para el enrutamiento de tuplas o el destino especificado en el comando.

Si el puntero BeginForeignInsert se establece en NULL, no se realiza ninguna acción para la inicialización.

Ten en cuenta que si el FDW no admite particiones de tablas externas enrutables y/o ejecutar COPY FROM en tablas externas, esta función o ExecForeignInsert/ExecForeignBatchInsert llamadas posteriormente deben lanzar un error según sea necesario.

void
EndForeignInsert(EState *estate,
                 ResultRelInfo *rinfo);

Finaliza la operación de inserción y libera los recursos. Normalmente no es importante liberar la memoria asignada con palloc, pero por ejemplo, se deben cerrar los archivos abiertos y las conexiones a servidores remotos.

Si el puntero EndForeignInsert se establece en NULL, no se realiza ninguna acción para la finalización.

int
IsForeignRelUpdatable(Relation rel);

Informa qué operaciones de actualización admite la tabla externa especificada. El valor de retorno debe ser una máscara de bits de números de eventos de reglas que indiquen qué operaciones son compatibles con la tabla externa, utilizando la enumeración CmdType; es decir, (1 << CMD_UPDATE) = 4 para UPDATE, (1 << CMD_INSERT) = 8 for INSERT, y (1 << CMD_DELETE) = 16 para DELETE.

Si el puntero IsForeignRelUpdatable se establece en NULL, se asume que las tablas externas admiten inserciones, actualizaciones o eliminaciones si el FDW proporciona ExecForeignInsert, ExecForeignUpdate, o ExecForeignDelete respectivamente. Esta función solo es necesaria si el FDW admite algunas tablas que son actualizables y otras que no lo son. (Incluso en ese caso, es admisible lanzar un error en la rutina de ejecución en lugar de verificarlo en esta función. Sin embargo, esta función se usa para determinar la capacidad de actualización para mostrarla en las vistas de information_schema).

Algunas inserciones, actualizaciones y eliminaciones en tablas externas pueden optimizarse implementando un conjunto alternativo de interfaces. Las interfaces ordinarias para inserciones, actualizaciones y eliminaciones obtienen las filas del servidor remoto y luego modifican esas filas una a la vez. En algunos casos, este enfoque fila por fila es necesario, pero puede ser ineficiente. Si es posible que el servidor remoto determine qué filas deben modificarse sin tener que recuperarlas realmente, y si no hay estructuras locales que afecten la operación (disparadores locales a nivel de fila, columnas generadas almacenadas o restricciones WITH CHECK OPTION de vistas padre), entonces es posible organizar las cosas para que toda la operación se realice en el servidor remoto. Las interfaces descritas a continuación hacen esto posible.

bool
PlanDirectModify(PlannerInfo *root,
                 ModifyTable *plan,
                 Index resultRelation,
                 int subplan_index);

Decide si es seguro ejecutar una modificación directa en el servidor remoto. Si es así, devuelve true después de realizar las acciones de planificación necesarias para ello. De lo contrario, devuelve false. Esta función opcional se llama durante la planificación de la consulta. Si esta función tiene éxito, se llamará a BeginDirectModify, IterateDirectModify y EndDirectModify en la etapa de ejecución, en su lugar. De lo contrario, la modificación de la tabla se ejecutará utilizando las funciones de actualización descritas anteriormente. Los parámetros son los mismos que para PlanForeignModify.

Para ejecutar la modificación directa en el servidor remoto, esta función debe reescribir el subplan de destino con un nodo de plan ForeignScan que ejecute la modificación directa en el servidor remoto. Los campos operation y resultRelation de ForeignScan deben establecerse de manera adecuada. operation debe establecerse en la enumeración CmdType correspondiente al tipo de sentencia (es decir, CMD_UPDATE para UPDATE, CMD_INSERT para INSERT, y CMD_DELETE para DELETE), y el argumento resultRelation debe copiarse al campo resultRelation.

Consulta la Section 58.4 para obtener información adicional.

Si el puntero PlanDirectModify se establece en NULL, no se realizan intentos de ejecutar una modificación directa en el servidor remoto.

void
BeginDirectModify(ForeignScanState *node,
                  int eflags);

Se prepara para ejecutar una modificación directa en el servidor remoto. Se llama durante el inicio del ejecutor. Debe realizar cualquier inicialización necesaria antes de la modificación directa (que debe hacerse en la primera llamada a IterateDirectModify). El nodo ForeignScanState ya ha sido creado, pero su campo fdw_state sigue siendo NULL. La información sobre la tabla a modificar es accesible a través del nodo ForeignScanState (en particular, desde el nodo de plan ForeignScan subyacente, que contiene cualquier información privada de FDW proporcionada por PlanDirectModify). eflags contiene bits de banderas que describen el modo de funcionamiento del ejecutor para este nodo de plan.

Ten en cuenta que cuando (eflags & EXEC_FLAG_EXPLAIN_ONLY) es verdadero, esta función no debe realizar ninguna acción externamente visible; solo debe hacer lo mínimo requerido para que el estado del nodo sea válido para ExplainDirectModify y EndDirectModify.

Si el puntero BeginDirectModify se establece en NULL, no se realizan intentos de ejecutar una modificación directa en el servidor remoto.

TupleTableSlot *
IterateDirectModify(ForeignScanState *node);

Cuando la consulta INSERT, UPDATE o DELETE no tiene una cláusula RETURNING, simplemente devuelve NULL después de una modificación directa en el servidor remoto. Cuando la consulta tiene la cláusula, obtiene un resultado que contiene los datos necesarios para el cálculo de RETURNING, devolviéndolo en una ranura de tabla de tuplas (se debe usar la ranura ScanTupleSlot del nodo para este propósito). Los datos que realmente se insertaron, actualizaron o eliminaron deben almacenarse en node->resultRelInfo->ri_projectReturning->pi_exprContext->ecxt_scantuple. Devuelve NULL si no hay más filas disponibles. Ten en cuenta que esto se llama en un contexto de memoria de corta duración que se restablecerá entre invocaciones. Crea un contexto de memoria en BeginDirectModify si necesitas un almacenamiento de mayor duración, o usa el es_query_cxt del EState del nodo.

Las filas devueltas deben coincidir con la lista de objetivos fdw_scan_tlist si se proporcionó una, de lo contrario deben coincidir con el tipo de fila de la tabla externa que se está actualizando. Si decides optimizar omitiendo la obtención de columnas que no son necesarias para el cálculo de RETURNING, debes insertar nulos en esas posiciones de columna, o bien generar una lista fdw_scan_tlist con esas columnas omitidas.

Independientemente de si la consulta tiene la cláusula o no, el recuento de filas reportado por la consulta debe ser incrementado por el propio FDW. Cuando la consulta no tiene la cláusula, el FDW también debe incrementar el recuento de filas para el nodo ForeignScanState en el caso de EXPLAIN ANALYZE.

Si el puntero IterateDirectModify se establece en NULL, no se realizan intentos de ejecutar una modificación directa en el servidor remoto.

void
EndDirectModify(ForeignScanState *node);

Limpia después de una modificación directa en el servidor remoto. Normalmente no es importante liberar la memoria asignada con palloc, pero por ejemplo, se deben cerrar los archivos abiertos y las conexiones al servidor remoto.

Si el puntero EndDirectModify se establece en NULL, no se realizan intentos de ejecutar una modificación directa en el servidor remoto.

58.2.5. Rutinas de FDW para TRUNCATE #

void
ExecForeignTruncate(List *rels,
                    DropBehavior behavior,
                    bool restart_seqs);

Vacía (truncate) tablas externas. Esta función se llama cuando se ejecuta TRUNCATE en una tabla externa. rels is una lista de estructuras de datos Relation de las tablas externas a vaciar.

behavior es DROP_RESTRICT o DROP_CASCADE, lo que indica que se solicitó la opción RESTRICT o CASCADE en el comando TRUNCATE original, respectivamente.

Si restart_seqs es true, el comando TRUNCATE original solicitó el comportamiento RESTART IDENTITY, de lo contrario se solicitó el comportamiento CONTINUE IDENTITY.

Ten en cuenta que las opciones ONLY especificadas en el comando TRUNCATE original no se pasan a ExecForeignTruncate. Este comportamiento es similar al de las funciones de retrollamada de SELECT, UPDATE y DELETE en una tabla externa.

ExecForeignTruncate se invoca una vez por servidor externo para el cual se van a vaciar las tablas externas. Esto significa que todas las tablas externas incluidas en rels deben pertenecer al mismo servidor.

Si el puntero ExecForeignTruncate se establece en NULL, los intentos de vaciar tablas externas fallarán con un mensaje de error.

58.2.6. Rutinas de FDW para el bloqueo de filas #

Si un FDW desea admitir el bloqueo tardío de filas (late row locking) (como se describe en la Section 58.5), debe proporcionar las siguientes funciones de retrollamada:

RowMarkType
GetForeignRowMarkType(RangeTblEntry *rte,
                      LockClauseStrength strength);

Informa qué opción de marcado de filas usar para una tabla externa. rte es el nodo RangeTblEntry para la tabla y strength describe la fuerza del bloqueo solicitada por la cláusula FOR UPDATE/SHARE relevante, si la hay. El resultado debe ser un miembro del tipo enumerado RowMarkType.

Esta función se llama durante la planificación de la consulta para cada tabla externa que aparece en una consulta UPDATE, DELETE o SELECT FOR UPDATE/SHARE y no es el destino de UPDATE o DELETE.

Si el puntero GetForeignRowMarkType se establece en NULL, siempre se utiliza la opción ROW_MARK_COPY. (Esto implica que RefetchForeignRow nunca se llamará, por lo que tampoco es necesario proporcionarla).

Consulta la Section 58.5 para obtener más información.

void
RefetchForeignRow(EState *estate,
                  ExecRowMark *erm,
                  Datum rowid,
                  TupleTableSlot *slot,
                  bool *updated);

Vuelve a obtener una ranura de tupla de la tabla externa, después de bloquearla si es necesario. estate es el estado de ejecución global para la consulta. erm es la estructura ExecRowMark que describe la tabla externa de destino y el tipo de bloqueo de fila (si lo hay) a adquirir. rowid identifica la tupla a obtener. slot no contiene nada útil al ser llamada, pero se puede usar para contener la tupla devuelta. updated es un parámetro de salida.

Esta función debe almacenar la tupla en la ranura proporcionada, o limpiarla si no se pudo obtener el bloqueo de fila. El tipo de bloqueo de fila a adquirir se define mediante erm->markType, que es el valor devuelto previamente por GetForeignRowMarkType. (ROW_MARK_REFERENCE significa simplemente volver a obtener la tupla sin adquirir ningún bloqueo, y esta rutina nunca verá ROW_MARK_COPY).

Además, *updated debe establecerse en true si lo que se obtuvo fue una versión actualizada de la tupla en lugar de la misma versión obtenida anteriormente. (Si el FDW no puede estar seguro de esto, se recomienda devolver siempre true).

Ten en cuenta que, por defecto, el fallo al adquirir un bloqueo de fila debe resultar en el lanzamiento de un error; devolver una ranura vacía solo es apropiado si la opción SKIP LOCKED está especificada por erm->waitPolicy.

El rowid es el valor de ctid leído previamente para la fila a volver a obtener. Aunque el valor de rowid se pasa como un Datum, actualmente solo puede ser un tid. Se elige la API de la función con la esperanza de que sea posible permitir otros tipos de datos para los ID de fila en el futuro.

Si el puntero RefetchForeignRow se establece en NULL, los intentos de volver a obtener filas fallarán con un mensaje de error.

Consulta la Section 58.5 para obtener más información.

bool
RecheckForeignScan(ForeignScanState *node,
                   TupleTableSlot *slot);

Vuelve a comprobar que una tupla devuelta previamente siga coincidiendo con los calificadores de escaneo y unión pertinentes, y posiblemente proporciona una versión modificada de la tupla. Para los adaptadores de datos externos que no realizan la inserción de uniones (join pushdown), normalmente será más conveniente establecer esto en NULL y, en su lugar, configurar fdw_recheck_quals adecuadamente. Sin embargo, cuando se empujan hacia abajo las uniones externas, no es suficiente volver a aplicar los controles pertinentes a todas las tablas base a la tupla de resultado, incluso si todos los atributos necesarios están presentes, porque el fallo en la coincidencia de algún calificador podría hacer que algunos atributos pasen a ser NULL, en lugar de que no se devuelva ninguna tupla. RecheckForeignScan puede volver a comprobar los calificadores y devolver true si todavía se cumplen y false en caso contrario, pero también puede almacenar una tupla de reemplazo en la ranura suministrada.

Para implementar la inserción de uniones, un adaptador de datos externos normalmente construirá un plan de unión local alternativo que se utiliza solo para las recomprobaciones; este se convertirá en el subplan externo del ForeignScan. Cuando se requiere una recomprobación, este subplan se puede ejecutar y la tupla resultante se puede almacenar en la ranura. Este plan no necesita ser eficiente ya que ninguna tabla base devolverá más de una fila; por ejemplo, puede implementar todas las uniones como bucles anidados. La función GetExistingLocalJoinPath se puede usar para buscar en las rutas existentes una ruta de unión local adecuada, que se puede usar como el plan de unión local alternativo. GetExistingLocalJoinPath busca una ruta no parametrizada en la lista de rutas de la relación de unión especificada. (Si no encuentra dicha ruta, devuelve NULL, en cuyo caso un adaptador de datos externos puede construir la ruta local por sí mismo o puede optar por no crear rutas de acceso para esa unión).

58.2.7. Rutinas de FDW para EXPLAIN #

void
ExplainForeignScan(ForeignScanState *node,
                   ExplainState *es);

Imprime salida adicional de EXPLAIN para un escaneo de tabla externa. Esta función puede llamar a ExplainPropertyText y funciones relacionadas para añadir campos a la salida de EXPLAIN. Los campos de banderas en es se pueden usar para determinar qué imprimir, y el estado del nodo ForeignScanState se puede inspeccionar para proporcionar estadísticas de tiempo de ejecución en el caso de EXPLAIN ANALYZE.

Si el puntero ExplainForeignScan se establece en NULL, no se imprime información adicional durante un EXPLAIN.

void
ExplainForeignModify(ModifyTableState *mtstate,
                     ResultRelInfo *rinfo,
                     List *fdw_private,
                     int subplan_index,
                     struct ExplainState *es);

Imprime salida adicional de EXPLAIN para una actualización de tabla externa. Esta función puede llamar a ExplainPropertyText y funciones relacionadas para añadir campos a la salida de EXPLAIN. Los campos de banderas en es se pueden usar para determinar qué imprimir, y el estado del nodo ModifyTableState se puede inspeccionar para proporcionar estadísticas de tiempo de ejecución en el caso de EXPLAIN ANALYZE. Los primeros cuatro argumentos son los mismos que para BeginForeignModify.

Si el puntero ExplainForeignModify se establece en NULL, no se imprime información adicional durante un EXPLAIN.

void
ExplainDirectModify(ForeignScanState *node,
                    ExplainState *es);

Imprime salida de EXPLAIN adicional para una modificación directa en el servidor remoto. Esta función puede llamar a ExplainPropertyText y funciones relacionadas para añadir campos a la salida de EXPLAIN. Los campos de banderas en es se pueden usar para determinar qué imprimir, y el estado del nodo ForeignScanState se puede inspeccionar para proporcionar estadísticas de tiempo de ejecución en el caso de EXPLAIN ANALYZE.

Si el puntero ExplainDirectModify se establece en NULL, no se imprime información adicional durante un EXPLAIN.

58.2.8. Rutinas de FDW para ANALYZE #

bool
AnalyzeForeignTable(Relation relation,
                    AcquireSampleRowsFunc *func,
                    BlockNumber *totalpages);

Esta función se llama cuando se ejecuta ANALYZE en una tabla externa. Si el FDW puede recopilar estadísticas para esta tabla externa, debe devolver true y proporcionar un puntero a una función que recopilará filas de muestra de la tabla en func, más el tamaño estimado de la tabla en páginas en totalpages. De lo contrario, devuelve false.

If el FDW no admite la recopilación de estadísticas para ninguna tabla, el puntero AnalyzeForeignTable se puede establecer en NULL.

Si se proporciona, la función de recopilación de muestras debe tener la firma:

int
AcquireSampleRowsFunc(Relation relation,
                      int elevel,
                      HeapTuple *rows,
                      int targrows,
                      double *totalrows,
                      double *totaldeadrows);

Se debe recopilar una muestra aleatoria de hasta targrows filas de la tabla y almacenarse en el array rows proporcionado por el invocador. Se debe devolver el número real de filas recopiladas. Además, almacena estimaciones de los números totales de filas vivas y muertas en la tabla en los parámetros de salida totalrows y totaldeadrows. (Establece totaldeadrows en cero si el FDW no tiene ningún concepto de filas muertas).

58.2.9. Rutinas de FDW para IMPORT FOREIGN SCHEMA #

List *
ImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid);

Obtiene una lista de comandos de creación de tablas externas. Esta función se llama al ejecutar IMPORT FOREIGN SCHEMA, y se le pasa el árbol de análisis (parse tree) para esa sentencia, así como el OID del servidor externo a usar. Debe devolver una lista de cadenas de C, cada una de las cuales debe contener un comando CREATE FOREIGN TABLE. Estas cadenas serán analizadas y ejecutadas por el servidor principal.

Dentro de la estructura ImportForeignSchemaStmt, remote_schema es el nombre del esquema remoto desde el cual se van a importar las tablas. list_type identifica cómo filtrar los nombres de las tablas: FDW_IMPORT_SCHEMA_ALL significa que se deben importar todas las tablas del esquema remoto (en este caso table_list está vacía), FDW_IMPORT_SCHEMA_LIMIT_TO significa incluir solo las tablas enumeradas en table_list, y FDW_IMPORT_SCHEMA_EXCEPT significa excluir las tablas enumeradas en table_list. options es una lista de opciones utilizadas para el proceso de importación. El significado de las opciones depende del FDW. Por ejemplo, un FDW podría usar una opción para definir si se deben importar los atributos NOT NULL de las columnas. Estas opciones no tienen por qué tener nada que ver con las admitidas por el FDW como opciones de objeto de base de datos.

El FDW puede ignorar el campo local_schema de la estructura ImportForeignSchemaStmt, porque el servidor principal insertará automáticamente ese nombre en los comandos CREATE FOREIGN TABLE analizados.

El FDW tampoco tiene que preocuparse por implementar el filtrado especificado por list_type y table_list, ya que el servidor principal omitirá automáticamente cualquier comando devuelto para las tablas excluidas según esas opciones. Sin embargo, a menudo es útil para evitar el trabajo de crear comandos para tablas excluidas en primer lugar. La función IsImportableForeignTable() puede ser útil para probar si un nombre de tabla externa dado pasará el filtro.

Si el FDW no admite la importación de definiciones de tablas, el puntero ImportForeignSchema se puede establecer en NULL.

58.2.10. Rutinas de FDW para ejecución paralela #

Un nodo ForeignScan puede, opcionalmente, admitir la ejecución en paralelo. Un ForeignScan en paralelo se ejecutará en múltiples procesos y debe devolver cada fila exactamente una vez entre todos los procesos que cooperan. Para hacer esto, los procesos pueden coordinarse a través de fragmentos de tamaño fijo de memoria compartida dinámica. No se garantiza que esta memoria compartida esté mapeada en la misma dirección en cada proceso, por lo que no debe contener punteros. Las siguientes funciones son todas opcionales, pero la mayoría son requeridas si se va a admitir la ejecución en paralelo.

bool
IsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel,
                           RangeTblEntry *rte);

Comprueba si se puede realizar un escaneo dentro de un trabajador en paralelo. Esta función solo se llamará cuando el planificador crea que un plan paralelo podría ser posible, y debe devolver true si es seguro que ese escaneo se ejecute dentro de un trabajador paralelo. Este no será el caso generalmente si la fuente de datos remota tiene semántica de transacción, a menos que la conexión del trabajador a los datos se pueda hacer de alguna manera para compartir el mismo contexto de transacción que el líder.

If esta función no está definida, se asume que el escaneo debe realizarse dentro del líder en paralelo. Ten en cuenta que devolver true no significa que el escaneo en sí pueda realizarse en paralelo, solo que el escaneo se puede realizar dentro de un trabajador en paralelo. Por lo tanto, puede ser útil definir este método incluso cuando la ejecución en paralelo no sea compatible.

Size
EstimateDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt);

Estima la cantidad de memoria compartida dinámica que se requerirá para la operación en paralelo. Esto puede ser mayor que la cantidad que realmente se usará, pero no debe ser menor. El valor de retorno es en bytes. Esta función es opcional y puede omitirse si no es necesaria; pero si se omite, las siguientes tres funciones también deben omitirse, ya que no se asignará memoria compartida para el uso del FDW.

void
InitializeDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt,
                         void *coordinate);

Inicializa la memoria compartida dinámica que se requerirá para la operación paralela. coordinate apunta a un área de memoria compartida de tamaño igual al valor de retorno de EstimateDSMForeignScan. Esta función es opcional y puede omitirse si no es necesaria.

void
ReInitializeDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt,
                           void *coordinate);

Vuelve a inicializar la memoria compartida dinámica requerida para la operación paralela cuando el nodo de plan de escaneo externo está a punto de volver a escanearse. Esta función es opcional y puede omitirse si no es necesaria. La práctica recomendada es que esta función restablezca solo el estado compartido, mientras que la función ReScanForeignScan restablece solo el estado local. Actualmente, esta función se llamará antes de ReScanForeignScan, pero es mejor no confiar en ese orden.

void
InitializeWorkerForeignScan(ForeignScanState *node, shm_toc *toc,
                            void *coordinate);

Inicializa el estado local de un trabajador paralelo basándose en el estado compartido configurado por el líder durante InitializeDSMForeignScan. Esta función es opcional y puede omitirse si no es necesaria.

void
ShutdownForeignScan(ForeignScanState *node);

Libera recursos cuando se prevé que el nodo no se ejecutará hasta su finalización. Esto no se llama en todos los casos; a veces, se puede llamar a EndForeignScan sin que esta función se haya llamado primero. Dado que el segmento DSM utilizado por la consulta paralela se destruye justo después de que se invoque esta retrollamada, los adaptadores de datos externos que deseen realizar alguna acción antes de que el segmento DSM desaparezca deben implementar este método.

58.2.11. Rutinas de FDW para ejecución asíncrona #

Un nodo ForeignScan puede, opcionalmente, admitir la ejecución asíncrona como se describe en src/backend/executor/README. Las siguientes funciones son todas opcionales, pero son requeridas si se va a admitir la ejecución asíncrona.

bool
IsForeignPathAsyncCapable(ForeignPath *path);

Comprueba si una ruta ForeignPath dada puede escanear la relación externa subyacente de forma asíncrona. Esta función solo se llamará al final de la planificación de la consulta cuando la ruta dada sea hija directa de una ruta AppendPath y cuando el planificador crea que la ejecución asíncrona mejora el rendimiento, y debe devolver true si la ruta dada es capaz de escanear la relación externa de forma asíncrona.

Si esta función no está definida, se asume que la ruta dada escanea la relación externa usando IterateForeignScan. (Esto implica que las funciones de retrollamada descritas a continuación nunca se llamarán, por lo que tampoco es necesario proporcionarlas).

void
ForeignAsyncRequest(AsyncRequest *areq);

Produce una tupla de forma asíncrona desde el nodo ForeignScan. areq es la estructura AsyncRequest que describe el nodo ForeignScan y el nodo Append padre que solicitó la tupla de este. Esta función debe almacenar la tupla en la ranura especificada por areq->result, y establecer areq->request_complete en true; o bien, si necesita esperar un evento externo al servidor principal, como E/S de red, y no puede producir ninguna tupla inmediatamente, establecer la bandera en false, y establecer areq->callback_pending en true para que el nodo ForeignScan obtenga una llamada de las funciones de retrollamada descritas a continuación. Si no hay más tuplas disponibles, establece la ranura en NULL o en una ranura vacía, y la bandera areq->request_complete en true. Se recomienda usar ExecAsyncRequestDone o ExecAsyncRequestPending para configurar los parámetros de salida en areq.

void
ForeignAsyncConfigureWait(AsyncRequest *areq);

Configura un evento de descriptor de archivo por el cual el nodo ForeignScan desea esperar. Esta función solo se llamará cuando el nodo ForeignScan tenga establecida la bandera areq->callback_pending, y debe añadir el evento al campo as_eventset del nodo Append padre descrito por el parámetro areq. Consulta los comentarios para ExecAsyncConfigureWait en src/backend/executor/execAsync.c para obtener información adicional. Cuando ocurra el evento del descriptor de archivo, se llamará a ForeignAsyncNotify.

void
ForeignAsyncNotify(AsyncRequest *areq);

Procesa un evento relevante que ha ocurrido, luego produce una tupla de forma asíncrona desde el nodo ForeignScan. Esta función debe configurar los parámetros de salida en areq de la misma manera que ForeignAsyncRequest.

58.2.12. Rutinas de FDW para la parametrización de rutas #

List *
ReparameterizeForeignPathByChild(PlannerInfo *root, List *fdw_private,
                                 RelOptInfo *child_rel);

Esta función se llama al convertir una ruta parametrizada por el padre de nivel superior de la relación hija dada child_rel para que sea parametrizada por la relación hija. La función se utiliza para parametrizar de nuevo cualquier ruta o traducir cualquier nodo de expresión guardado en el miembro fdw_private dado de una ruta ForeignPath. La retrollamada puede usar reparameterize_path_by_child, adjust_appendrel_attrs o adjust_appendrel_attrs_multilevel según sea necesario.