68.1. Reglas de declaración de catálogos del sistema #

La parte clave de un archivo de cabecera de catálogo es una definición de estructura C que describe la disposición de cada fila del catálogo. Esto comienza con una macro CATALOG, que para el compilador de C es simplemente una forma abreviada de typedef struct FormData_catalogname. Cada campo de la estructura da lugar a una columna del catálogo. Los campos se pueden anotar utilizando las macros de propiedades BKI descritas en genbki.h, por ejemplo para definir un valor por defecto para un campo o marcarlo como anulable o no anulable. La línea CATALOG también se puede anotar, con algunas otras macros de propiedades BKI descritas en genbki.h, para definir otras propiedades del catálogo en su conjunto, como si es una relación compartida (shared).

El código de la caché del catálogo del sistema (y la mayor parte del código de manipulación de catálogos en general) asume que las partes de longitud fija de todas las tuplas del catálogo del sistema están de hecho presentes, porque mapea esta declaración de estructura C sobre ellas. Por lo tanto, todos los campos de longitud variable y los campos anulables deben colocarse al final, y no se puede acceder a ellos como campos de la estructura. Por ejemplo, si intentaras establecer pg_type.typrelid como NULL, fallaría cuando alguna parte del código intentara hacer referencia a typetup->typrelid (o peor aún, typetup->typelem, porque eso sigue a typrelid). Esto provocaría errores aleatorios o incluso fallos de segmentación.

Como protección parcial contra este tipo de error, los campos de longitud variable o anulables no deben hacerse directamente visibles al compilador de C. Esto se logra envolviéndolos en #ifdef CATALOG_VARLEN ... #endif (donde CATALOG_VARLEN es un símbolo que nunca se define). Esto evita que el código C intente descuidadamente acceder a campos que podrían no estar allí o que podrían estar en algún otro desplazamiento. Como protección independiente contra la creación de filas incorrectas, requerimos que todas las columnas que no deban ser anulables se marquen como tales en pg_attribute. El código de bootstrap marcará automáticamente las columnas del catálogo como NOT NULL si son de ancho fijo y no están precedidas por ninguna columna anulable o de ancho variable. Cuando esta regla sea insuficiente, puedes forzar el marcado correcto utilizando las anotaciones BKI_FORCE_NOT_NULL y BKI_FORCE_NULL según sea necesario.

El código del frontend no debe incluir ningún archivo de cabecera de catálogo pg_xxx.h, ya que estos archivos pueden contener código C que no se compilará fuera del backend. (Típicamente, esto sucede porque estos archivos también contienen declaraciones de funciones en los archivos de src/backend/catalog/). En su lugar, el código del frontend puede incluir la correspondiente cabecera generada pg_xxx_d.h, que contendrá los #define de OID y cualquier otro dato que pueda ser útil en el lado del cliente. Si deseas que las macros u otro código de una cabecera de catálogo sean visibles para el código del frontend, escribe #ifdef EXPOSE_TO_CLIENT_CODE ... #endif alrededor de esa sección para indicarle a genbki.pl que copie esa sección en la cabecera pg_xxx_d.h.

Algunos de los catálogos son tan fundamentales que ni siquiera pueden ser creados por el comando create de BKI que se utiliza para la mayoría de los catálogos, porque ese comando necesita escribir información en estos catálogos para describir el nuevo catálogo. Estos se denominan catálogos de bootstrap (arranque inicial), y definir uno requiere mucho trabajo extra: tienes que preparar manualmente las entradas adecuadas para ellos en los contenidos precargados de pg_class y pg_type, y esas entradas deberán actualizarse para posteriores cambios en la estructura del catálogo. (Los catálogos de bootstrap también necesitan entradas precargadas en pg_attribute, pero afortunadamente genbki.pl se encarga de esa tarea hoy en día). Evita que los nuevos catálogos sean catálogos de bootstrap si es posible.