El código en PostgreSQL solo debe depender de las características del lenguaje disponibles en el estándar C99. Esto significa que un compilador conforme a C99 tiene que ser capaz de compilar postgres, al menos aparte de unas pocas piezas que dependen de la plataforma.
Actualmente, no se permite utilizar algunas características incluidas en el estándar C99 en el código principal
de PostgreSQL. Esto incluye actualmente los arrays de longitud variable, las
declaraciones mezcladas con código, los comentarios de tipo // y los nombres de caracteres
universales. Las razones para ello incluyen la portabilidad y las prácticas históricas.
Se pueden utilizar características de revisiones posteriores del estándar C o características específicas del compilador, siempre que se proporcione una alternativa (fallback).
Por ejemplo, actualmente se utilizan _Static_assert() y __builtin_constant_p,
a pesar de que pertenecen a revisiones más nuevas del estándar C y a una extensión de GCC
respectivamente. Si no están disponibles, recurrimos respectivamente al uso de un reemplazo compatible con C99
que realiza las mismas comprobaciones pero emite mensajes bastante crípticos, y no utilizamos
__builtin_constant_p.
Se pueden utilizar tanto macros con argumentos como funciones static inline. Estas últimas
son preferibles si existen riesgos de evaluación múltiple cuando se escriben como macro, como ocurre, por ejemplo,
con:
#define Max(x, y) ((x) > (y) ? (x) : (y))
o cuando la macro sería muy larga. En otros casos, solo es posible utilizar macros, o al menos resulta más fácil. Por ejemplo, porque es necesario pasar expresiones de varios tipos a la macro.
Cuando la definición de una función en línea hace referencia a símbolos (es decir, variables, funciones) que solo están disponibles como parte del backend, es posible que la función no sea visible cuando se incluye desde el código del frontend.
#ifndef FRONTEND
static inline MemoryContext
MemoryContextSwitchTo(MemoryContext context)
{
MemoryContext old = CurrentMemoryContext;
CurrentMemoryContext = context;
return old;
}
#endif /* FRONTEND */
En este ejemplo se hace referencia a CurrentMemoryContext, que solo está disponible en el backend,
y la función queda oculta con un #ifndef FRONTEND. Esta regla existe porque algunos compiladores
emiten referencias a símbolos contenidos en funciones en línea incluso si la función no se utiliza.
Para ser adecuado para ejecutarse dentro de un manejador de señales, el código debe escribirse con mucho cuidado. El problema fundamental es que, a menos que esté bloqueado, un manejador de señales puede interrumpir el código en cualquier momento. Si el código dentro del manejador de señales utiliza el mismo estado que el código exterior, puede desatarse el caos. Como ejemplo, considera qué sucede si un manejador de señales intenta adquirir un bloqueo que ya se tiene en el código interrumpido.
Salvo disposiciones especiales, el código en los manejadores de señales solo puede llamar a funciones seguras para
señales asíncronas (async-signal safe, según se define en POSIX) y acceder a variables de tipo
volatile sig_atomic_t. También se consideran seguras para señales unas pocas funciones en
postgres, de manera importante SetLatch().
En la mayoría de los casos, los manejadores de señales no deberían hacer nada más que registrar que ha llegado una señal y despertar el código que se ejecuta fuera del manejador utilizando un latch. Un ejemplo de este tipo de manejador es el siguiente:
static void
handle_sighup(SIGNAL_ARGS)
{
got_SIGHUP = true;
SetLatch(MyLatch);
}
Para mayor claridad, se prefiere desreferenciar explícitamente un puntero de función al llamar a la función a la que apunta si el puntero es una variable simple, por ejemplo:
(*emit_log_hook) (edata);
(aunque emit_log_hook(edata) también funcionaría). Cuando el puntero de función forma parte
de una estructura, entonces la puntuación adicional se puede y normalmente se debe omitir, por ejemplo:
paramInfo->paramFetch(paramInfo, paramId);