Различные соглашения по оформлению кода#

Стандарт C#

Код PostgreSQL должен опираться только на возможности языка, доступные в стандарте C99. Это означает, что компилятор, соответствующий стандарту C99, должен уметь компилировать Postgres, по крайней мере, за исключением нескольких частей, зависящих от платформы.

Некоторые возможности, включенные в стандарт C99, на данный момент не разрешены к использованию в основном коде Post- greSQL. В настоящее время это массивы переменной длины, перемежающиеся декларации и код, // комментарии, универсальные имена символов. Причины этого - переносимость и историческая практика.

Возможности из более поздних версий стандарта C или специфические возможности компилятора могут быть использованы, если предусмотрена обратная связь.

Например, в настоящее время используются _Static_assert() и _builtin_constant_p, несмотря на то, что они относятся к более новым редакциям стандарта C и расширению GCC соответственно. Если их нет, мы, соответственно, возвращаемся к использованию совместимой с C99 замены, которая выполняет те же проверки, но выдает довольно загадочные сообщения и не использует _builtin_constant_p.

Макросы, похожие на функции, и встроенные функции#

Можно использовать как макросы с аргументами, так и статические встроенные (static inline) функции. Последние предпочтительнее, если при записи в виде макроса существует опасность множественной оценки, как, например, в случае с:

\#define Max(x, y) ((x) \> (y) ? (x) : (y))

Или когда макрос будет очень длинным. В других случаях можно использовать только макросы или, по крайней мере, проще. Например, потому что в макрос нужно передавать выражения различных типов.

Когда определение встроенной функции ссылается на символы (например, переменные, функции), которые доступны только в бэкенде, функция может быть не видна при включении в код фронтенда.

#ifndef FRONTEND

static inline MemoryContext MemoryContextSwitchTo(MemoryContext context)

{

MemoryContext old = CurrentMemoryContext;

CurrentMemoryContext = context; return old;

}

#endif /* FRONTEND */

В данном примере используется ссылка на CurrentMemoryContext, которая доступна только в бэкенде, и поэтому функция скрыта с помощью #ifndef FRONTEND. Это правило существует потому, что некоторые компиляторы выдают ссылки на символы, содержащиеся во встроенных функциях, даже если функция не используется.

Написание обработчиков сигналов#

Чтобы код мог выполняться внутри обработчика сигналов, он должен быть написан очень тщательно. Основная проблема заключается в том, что, если обработчик сигналов не заблокирован, он может прервать выполнение кода в любой момент. Если код внутри обработчика сигналов использует то же состояние, что и код снаружи, может возникнуть хаос. В качестве примера рассмотрим, что произойдет, если обработчик сигнала попытается получить блокировку, которая уже находится в прерванном коде.

За исключением специальных договоренностей, код в обработчиках сигналов может вызывать только асинхронные сигналобезопасные функции (как определено в POSIX) и обращаться к переменным типа volatile sig_atomic_t. Несколько функций в postgres также считаются сигналобезопасными, в частности SetLatch().

В большинстве случаев обработчики сигналов не должны делать ничего, кроме как отмечать, что сигнал пришел, и пробуждать код, выполняющийся вне обработчика, с помощью защелки. Примером такого обработчика может служить следующее:

static void handle_sighup(SIGNAL_ARGS)

{

intsave_errno = errno;

got_SIGHUP = true; SetLatch(MyLatch);

errno = save_errno;

}

errno сохраняется и восстанавливается, потому что SetLatch() может его изменить. Если этого не сделать, то прерванный код, который в данный момент проверяет errno, может увидеть неправильное значение.

Вызов указателей функций#

Для ясности предпочтительнее явно разыменовывать указатель функции при вызове указанной функции, если указатель является простой переменной, например:

(\*emit_log_hook) (edata);

(хотя emit_log_hook(edata) тоже сработает). Если указатель функции является частью структуры, то лишние знаки препинания можно и обычно нужно опускать, например:

paramInfo->paramFetch(paramInfo, paramId);