Categories: PostgreSQL

postgresql-add-function/

При разработке пача для PostgreSQL иногда требуется добавить новую функцию, чтобы ее можно было вызывать из SQL. Недавно вопрос о том, как это делается, задали мне два разных человека в течение одной недели. И хотя это простая задача, информация, по всей видимости, является востребованной. Давайте же рассмотрим решение.

Рассматривать будем на примере конкретного пача 260a1f18 , добавляющего в ядро функции to_bin() и to_oct() :

=# SELECT to_bin(123);
to_bin
———
1111011

=# SELECT to_bin(255);
to_bin
———-
11111111

=# SELECT pg_typeof(to_bin(255));
pg_typeof
————
text

Добавление функции осуществляется путем редактирования файла pg_proc.dat.

Например:

{ oid => ‘9030’, descr => ‘convert int4 number to binary’,
proname => ‘to_bin’, prorettype => ‘text’, proargtypes => ‘int4’,
prosrc => ‘to_bin32’ },

Если функция имеет несколько аргументов ( proargtypes ), их типы указываются через пробел. Можно определить несколько функций с одинаковыми именами ( proname ), но разными аргументами или их количеством. Само собой разумеется, реализации функции на языке C при этом будут иметь разные имена ( prosrc ). Перегрузки функций по возвращаемому значению ( prorettype ) в PostgreSQL не предусмотренно. Описание функции ( descr ) — это то, что будет показываться в выводе df+ to_bin .

Для поиска свободного Oid есть специальный скрипт:

$ ./src/include/catalog/unused_oids

6312 — 8402
8404 — 9029
9034 — 9999
Patches should use a more-or-less consecutive range of OIDs.
Best practice is to start with a random choice in the range 8000-9999.
Suggested random unused OID: 9223 (777 consecutive OID(s) available ⏎
starting here)

Еще одно важное свойство функции — это volatility . Оно указывается при помощи параметра provolatile . Значение s говорит, что функция является STABLE . Для одних и тех же аргументов функция возвращает один и тот же результат в рамках одного SQL-выражения . Это поведение функций, к примеру, зависящих от параметров конфигурации (GUCs) . Значение v соответствует VOLATILE функциям. Это «грязные» функции в том смысле, что они могут иметь внутреннее состояние, ходить в файлы или сеть, и так далее. Если provolatile не указан, то функция является IMMUTABLE . Это как чистые функции в функциональном программировании . Их возвращаемое значение зависит только от аргументов.

Но есть нюансы. Например, функция, работающая с часовыми поясами при прочих равных считается IMMUTABLE . Несмотря на то, что обновление базы часовых поясов повлияет на возвращаемые ею значения, а также будет требовать перестройки индексов, если они использовали эту функцию. Также поведение IMMUTABLE функции может измениться при обновлении самого PostgreSQL. Например, если реализация содержала ошибку.

Не считая редактирования pg_proc.dat, написание новой функции ничем не отличается от написания новой функции для расширения — см один , два , три и далее по ссылкам. Конкретная реализация to_bin32() может быть найдена в файле varlena.c:

static inline text *
convert_to_base ( uint64 value , int base )
{
const char * digits = «0123456789abcdef» ;
char buf [ sizeof ( uint64 ) * BITS_PER_BYTE ] ;
char * const end = buf + sizeof ( buf ) ;
char * ptr = end ;

Assert ( base > 1 ) ;
Assert ( base <= 16 ) ;

do
{
*— ptr = digits [ value % base ] ;
value /= base ;
} while ( ptr > buf && value ) ;

return cstring_to_text_with_len ( ptr , end ptr ) ;
}

Datum
to_bin32 ( PG_FUNCTION_ARGS )
{
uint64 value = ( uint32 ) PG_GETARG_INT32 ( 0 ) ;

PG_RETURN_TEXT_P ( convert_to_base ( value , 2 ) ) ;
}

Помимо кода функции еще нужно добавить документацию и тесты. Это уже дело техники, а конкретные изменения могут быть найдены во все том же 260a1f18 . Поэтому не будем задерживаться на этом вопросе.

Напоследок хочется отметить два момента. Во-первых, некоторые функции имеет смысл добавлять не в ядро системы, а поместить в отдельное расширение — либо стороннее, либо идущее вместе с PostgreSQL и живущее в каталоге /contrib/ . Во-вторых, pg_proc.dat является удобной точкой входа для изучения внутренностей PostgreSQL. Также файл бывает полезен, когда вы примерно понимаете, какую функцию ищите, но не знаете ее название.

admin

Share
Published by
admin

Recent Posts

Лучшие дистрибутивы Linux

Если говорить о том, какие лучшие дистрибутивы Linux мы знаем, то этот список может быть…

1 месяц ago

Лучшие браузеры для Ubuntu

Хотя Ubuntu и поставляется со встроенным обозревателем Firefox многие пользователи считают что это не самая…

1 месяц ago

Установка Remmina Ubuntu 16.04 или 16.10

Что такое Remmina? Remmina — это совершенно бесплатный и свободный клиент так называемого удаленного рабочего…

1 месяц ago

Плюсы Ubuntu

Как мы знаем, Ubuntu это самая популярная сборка из систем на базе ядра Linux. У…

1 месяц ago

Выбираем ноутбук для Linux

Выбор ноутбука для каждого пользователя это довольно кропотливый процесс. Люди стараются подобрать ноутбук который будет…

1 месяц ago

Установка Linux рядом с Windows 10

Если вы решили ознакомиться с операционной системой Linux более детально и задались вопросом как установить…

1 месяц ago