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_.
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 catalognamegenbki.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.