← На главную

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

Расширениям 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.