Postgresql 中文操作指南

56.4. Miscellaneous Coding Conventions #

C Standard #

PostgreSQL 中的代码应该仅依赖 C99 标准中提供的语言功能。这意味着符合 C99 标准的编译器必须能够编译 postgres,至少除了几个与平台相关的内容外。

Code in PostgreSQL should only rely on language features available in the C99 standard. That means a conforming C99 compiler has to be able to compile postgres, at least aside from a few platform dependent pieces.

C99 标准中包含的一些功能目前不允许在 PostgreSQL 核心代码中使用。这目前包括可变长度数组、交错声明和代码、// 注释、通用字符名称。原因包括可移植性和历史实践。

A few features included in the C99 standard are, at this time, not permitted to be used in core PostgreSQL code. This currently includes variable length arrays, intermingled declarations and code, // comments, universal character names. Reasons for that include portability and historical practices.

如果提供了后备,则可以使用来自 C 标准的更高版本的版本或编译器特定的功能。

Features from later revisions of the C standard or compiler specific features can be used, if a fallback is provided.

例如 Static_assert()builtin_constant_p are currently used, even though they are from newer revisions of the C standard and a GCC extension respectively. If not available we respectively fall back to using a C99 compatible replacement that performs the same checks, but emits rather cryptic messages and do not use _builtin_constant_p

For example Static_assert() and builtin_constant_p_ are currently used, even though they are from newer revisions of the C standard and a GCC extension respectively. If not available we respectively fall back to using a C99 compatible replacement that performs the same checks, but emits rather cryptic messages and do not use builtin_constant_p.

Function-Like Macros and Inline Functions #

带有参数的宏和 static inline 函数都可以使用。如果以宏的形式编写时存在多重求值风险,后者更可取,因为例如,

Both macros with arguments and static inline functions may be used. The latter are preferable if there are multiple-evaluation hazards when written as a macro, as e.g., the case with

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

或者当宏非常长时。在其他情况下,只能使用宏,或者至少更容易。例如,因为各种类型的表达式需要传递给宏。

or when the macro would be very long. In other cases it’s only possible to use macros, or at least easier. For example because expressions of various types need to be passed to the macro.

当内联函数的定义引用仅作为后端的一部分可用的符号(即变量、函数)时,从前端代码中包含时可能无法看到该函数。

When the definition of an inline function references symbols (i.e., variables, functions) that are only available as part of the backend, the function may not be visible when included from frontend code.

#ifndef FRONTEND
static inline MemoryContext
MemoryContextSwitchTo(MemoryContext context)
{
    MemoryContext old = CurrentMemoryContext;

    CurrentMemoryContext = context;
    return old;
}
#endif   /* FRONTEND */

在此示例 CurrentMemoryContext 中,仅在后端中可用,因此被引用,并且函数因此使用 #ifndef FRONTEND 隐藏。此规则存在,因为即使该函数未使用,某些编译器也会发出引用内联函数中包含的符号的引用。

In this example CurrentMemoryContext, which is only available in the backend, is referenced and the function thus hidden with a #ifndef FRONTEND. This rule exists because some compilers emit references to symbols contained in inline functions even if the function is not used.

Writing Signal Handlers #

为了适合在信号处理程序中运行,必须非常小心地编写代码。根本问题在于,除非被阻止,否则信号处理程序可能会随时中断代码。如果信号处理程序中的代码与外部代码使用相同的状态,则可能会引起混乱。例如,考虑如果信号处理程序尝试获取中断代码中已持有的锁会发生什么情况。

To be suitable to run inside a signal handler code has to be written very carefully. The fundamental problem is that, unless blocked, a signal handler can interrupt code at any time. If code inside the signal handler uses the same state as code outside chaos may ensue. As an example consider what happens if a signal handler tries to acquire a lock that’s already held in the interrupted code.

除非有特殊安排,否则信号处理程序中的代码只能调用异步信号安全函数(如 POSIX 中定义的函数)并访问 volatile sig_atomic_t 类型的变量。postgres 中的部分函数也被认为是信号安全的,重要的是 SetLatch()

Barring special arrangements code in signal handlers may only call async-signal safe functions (as defined in POSIX) and access variables of type volatile sig_atomic_t. A few functions in postgres are also deemed signal safe, importantly SetLatch().

在大多数情况下,信号处理程序应该做的不仅仅是注意信号已经到达,并且使用锁闩唤醒在处理程序外部运行的代码。此类处理程序的一个示例如下:

In most cases signal handlers should do nothing more than note that a signal has arrived, and wake up code running outside of the handler using a latch. An example of such a handler is the following:

static void
handle_sighup(SIGNAL_ARGS)
{
    int         save_errno = errno;

    got_SIGHUP = true;
    SetLatch(MyLatch);

    errno = save_errno;
}

保存和恢复 errno,因为 SetLatch() 可能会更改它。如果没有这样做,当前正在检查 errno 的中断代码可能会看到错误的值。

errno is saved and restored because SetLatch() might change it. If that were not done interrupted code that’s currently inspecting errno might see the wrong value.

Calling Function Pointers #

为了清楚起见,最好在调用指向的函数时显式解除引用函数指针,如果指针是简单变量,例如:

For clarity, it is preferred to explicitly dereference a function pointer when calling the pointed-to function if the pointer is a simple variable, for example:

(*emit_log_hook) (edata);

(尽管 emit_log_hook(edata) 也适用)。当函数指针是结构的一部分时,可以而且通常应该省略额外的标点符号,例如:

(even though emit_log_hook(edata) would also work). When the function pointer is part of a structure, then the extra punctuation can and usually should be omitted, for example:

paramInfo->paramFetch(paramInfo, paramId);