Расширениям PostgreSQL могут требоваться какие-то параметры конфигурации. Для решения данной задачи в PostgreSQL имеется фреймворк под названием Grand Unified Configuration. GUC используется как расширениями, так и самой системой. Давайте же разберемся, как воспользоваться GUC из расширения.
Вот простейший пример:
#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
завершится ошибкой :
Приведенный код использует 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 .