Este capítulo explica la interfaz entre el sistema central de PostgreSQL y los métodos de acceso a tablas (table access methods), los cuales gestionan el almacenamiento de las tablas. El sistema central sabe poco acerca de estos métodos de acceso más allá de lo que se especifica aquí, por lo que es posible desarrollar tipos de métodos de acceso completamente nuevos escribiendo código adicional (add-on).
Cada método de acceso a tablas se describe mediante una fila en el catálogo
del sistema pg_am.
La entrada de pg_am especifica un nombre y una
función manejadora (handler function) para el método de acceso a tablas. Estas
entradas se pueden crear y eliminar utilizando los comandos SQL CREATE ACCESS METHOD and DROP ACCESS METHOD.
Una función manejadora de método de acceso a tablas debe declararse para aceptar un único
argumento de tipo internal y devolver el pseudotipo
table_am_handler. El argumento es un valor ficticio que simplemente
sirve para evitar que las funciones manejadoras se llamen directamente desde comandos SQL.
A continuación se muestra cómo un archivo de script SQL de extensión podría crear un manejador de método de acceso a tablas:
CREATE OR REPLACE FUNCTION my_tableam_handler(internal) RETURNS table_am_handler AS 'my_extension', 'my_tableam_handler' LANGUAGE C STRICT; CREATE ACCESS METHOD myam TYPE TABLE HANDLER my_tableam_handler;
El resultado de la función debe ser un puntero a una estructura de tipo
TableAmRoutine, que contiene todo lo que el
código central necesita saber para hacer uso del método de acceso a tablas. El valor
devuelto debe tener la duración de vida del servidor, lo que normalmente se logra
definiéndolo como una variable static const en el ámbito global.
A continuación se muestra cómo podría verse un archivo fuente con el manejador del método de acceso a tablas:
#include "postgres.h"
#include "access/tableam.h"
#include "fmgr.h"
PG_MODULE_MAGIC;
static const TableAmRoutine my_tableam_methods = {
.type = T_TableAmRoutine,
/* Los métodos de TableAmRoutine se omiten en este ejemplo, agrégalos aquí. */
};
PG_FUNCTION_INFO_V1(my_tableam_handler);
Datum
my_tableam_handler(PG_FUNCTION_ARGS)
{
PG_RETURN_POINTER(&my_tableam_methods);
}
La estructura TableAmRoutine, también llamada estructura
API del método de acceso, define el comportamiento del
método de acceso mediante retrollamadas (callbacks). Estas retrollamadas son punteros a
funciones C ordinarias y no son visibles ni invocables a nivel SQL. Todas las
retrollamadas y su comportamiento se definen en la estructura
TableAmRoutine (con comentarios dentro de la
estructura que definen los requisitos de cada retrollamada). La mayoría de las retrollamadas tienen
funciones envoltura (wrapper functions), las cuales están documentadas desde el punto de vista de un usuario
(en lugar de un implementador) del método de acceso a tablas. Para más detalles,
consulta el archivo
src/include/access/tableam.h.
Para implementar un método de acceso, un implementador normalmente necesitará
implementar un tipo de slot de tabla de tuplas (tuple table slot) específico del AM (consulta
src/include/executor/tuptable.h), el cual permite que el
código fuera del método de acceso mantenga referencias a las tuplas del AM, y
acceda a las columnas de la tupla.
Actualmente, la forma en que un AM almacena los datos es bastante libre. Por ejemplo, es posible, pero no obligatorio, utilizar la caché de búferes compartidos de postgres. En caso de utilizarse, probablemente tenga sentido usar el diseño de página estándar de PostgreSQL tal como se describe en Section 66.6.
Una restricción bastante grande de la API del método de acceso a tablas es que,
actualmente, si el AM desea admitir modificaciones y/o índices, es
necesario que cada tupla tenga un identificador de tupla (TID)
que consista en un número de bloque y un número de elemento (consulta también Section 66.6). No es estrictamente necesario que las
subpartes de los TIDs tengan el mismo significado que tienen por ejemplo
para heap, pero si se desea soporte para escaneo de mapa de bits (bitmap scan,
el cual es opcional), el número de bloque debe proporcionar localidad.
Para la seguridad ante fallos, un AM puede utilizar el WAL de postgres, o una implementación personalizada. Si se elige WAL, se pueden utilizar Registros WAL genéricos, o se puede implementar un Gestor de recursos WAL personalizado.
Para implementar el soporte transaccional de una manera que permita acceder a diferentes métodos de
acceso a tablas dentro de una sola transacción, probablemente sea
necesario integrarse estrechamente con la maquinaria de
src/backend/access/transam/xlog.c.
Cualquier desarrollador de un nuevo método de acceso a tablas puede consultar
la implementación de heap existente en
src/backend/access/heap/heapam_handler.c para obtener detalles sobre
su implementación.