Расширения PostgreSQL: конфигурационные параметры

31 июля 2023

Расширениям PostgreSQL могут требоваться какие-то параметры конфигурации. Для решения данной задачи в PostgreSQL имеется фреймворк под названием Grand Unified Configuration. GUC используется как расширениями, так и самой системой. Давайте же разберемся, как воспользоваться GUC из расширения.

Вот простейший пример:

#include <postgres.h>
#include <miscadmin.h>
#include <utils/builtins.h>
#include <utils/guc.h>

PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(experiment_get_message);

static char *message = NULL;

void
_PG_init(void)
{
    DefineCustomStringVariable("experiment.message",
                               "Short description here",
                               NULL,  /* длинное описание */
                               &message,
                               "",    /* начальное значение */
                               PGC_USERSET,
                               0,     /* флаги */
                               NULL,  /* check hook */
                               NULL,  /* assign hook */
                               NULL); /* show hook */

    /* Запрещаем регистрацию параметров с префиксом experiment */
    MarkGUCPrefixReserved("experiment");
}

Datum
experiment_get_message(PG_FUNCTION_ARGS)
{
    PG_RETURN_TEXT_P(cstring_to_text(message));
}

Это весь код расширения. Если вы пропустили мой рассказ про _PG_init(), ознакомьтесь с постом Расширения PostgreSQL: разделяемая память и локи.

Как видите, здесь все достаточно просто. Ядро системы предоставляет ряд функций с именами DefineCustomXXXVariable() для регистрации параметров конфигурации разных типов. Поддерживаются строки, числа, булевы значения и enum’ы. Подробности можно найти в guc.h и guc.c.

Код не должен вызывать особых вопросов, кроме, быть может, PGC_USERSET. Это значение типа GucContext. Оно определяет, кто и когда может менять параметр конфигурации. Например, если установить его в PGC_POSTMASTER, то параметр можно будет задавать только при старте СУБД. Попытка изменить значение командой SET, ALTER DATABASE или ALTER SYSTEM завершится ошибкой:

parameter "..." cannot be changed without restarting the server

Приведенный код использует PGC_USERSET. Это значит, что значение может менять кто угодно и когда угодно, в том числе, обычный пользователь в рамках своей сессии.

При тестировании кода с помощью TAP-тестов есть небольшой нюанс. Следует учитывать, что каждый вызов $node->safe_psql происходит в отдельной сессии. В связи с этим, код теста должен выглядеть как-то так:

# ...

$result = $node->safe_psql("postgres", qq{
SET experiment.message TO 'abc';
SELECT experiment_get_message();
});
ok($result eq "abc", 'SET has an effect');

# ...

Отдельные вызовы $node->safe_psql не приведут к желаемому результату.

Больше примеров вы найдете в расширениях из каталога contrib/. Например, в уже знакомом нам pg_stat_statements.c. В файле worker_spi.c показано, как можно узнать об изменении параметров из бэкграунд воркера.

Внимательный читатель мог заметить, что также поддерживаются хуки: check hook, assign hook и show hook. На практике они используются редко. Даже такое большое расширение как TimescaleDB в своем коде использует лишь пару хуков. И то, исключительно для того, чтобы предупредить пользователя о странных сочетаниях параметров. В связи с этим в данном посте хуки мы изучать не будем.

Исчерпывающие подробности описаны в соответствующем README. Но в 99% случаев достаточно информации, представленной выше.

Полная версия исходников к этому посту доступна на GitHub.

Метки: , , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.