Операционная система ЗОСРВ «Нейтрино» > Руководство разработчика > Программные интерфейсы общего назначения > Прикладные библиотеки и технологии > Библиотека менеджера QDB > Статьи и обзоры > Создание пользовательских функций



Создание пользовательских функций

Создание собственных SQL-функций и функций сортировки

В этой статье:

User scalar/aggregate functions
User collation routines
Example
sqlite C/C++ API
sqlite3_result_*
sqlite3_value_*
sqlite3_user_data

В QDB существуют два типа пользовательских функций: к первому типу относятся скалярные или агрегирующие функции, которые преобразуют данные, а ко второму типу — функции сортировки, которые упорядочивают данные. Скалярные функции вызываются с помощью SQL-оператора SELECT, а процедуры сортировки — с помощью условия COLLATE. ABS() является примером встроенной скалярной функции, а BINARY() —встроенной функции сортировки.

Чтобы предоставить службе QDB доступ к пользовательским функциям, необходимо скомпилировать их в динамическую библиотеку, а затем дать QDB команду загрузить ее, указав параметры Collation или Function для каждой функции в файле конфигурации базы данных.

User scalar/aggregate functions

Эти функции указываются в файле конфигурации с помощью параметра Function = tag@l.nosp@m.ibra.nosp@m.ry.so, где library.so — имя динамической библиотеки с кодом функции (абсолютный путь или имя файла, который находится в одном из каталогов, указанных в переменной окружения LD_LIBRARY_PATH), а tag — имя структуры struct qdb_function с описанием функции. Эти объекты определяются следующим образом:

static void myfunc( sqlite3_context *context, int narg, sqlite3_value **value )
{
...
}
struct qdb_function ftag = { "func",
SQLITE_UTF8,
1,
NULL,
myfunc,
NULL,
NULL };

Здесь ftag — тег, func — имя функции, которое распознается SQL, а myfunc() — вызываемая функция, которая может считывать четвертое поле (в данном примере NULL) с помощью sqlite3_user_data().


Note: Здесь имя ftag использовалось для иллюстрации; вместо него целесообразнее использовать имя func, которое совпадает с именем SQL.

В файле конфигурации можно определять несколько функций, которые находятся в одной или нескольких динамических библиотеках; каждой функции должна соответствовать одна запись Function= в файле конфигурации соответствующей базы данных, а также структура struct qdb_function с уникальным именем, которая описывает функцию.

User collation routines

Функции сортировки упорядочивают результаты оператора SQL: SELECT. Разработчик может определять собственные функции сортировки и выполнять их с помощью службы qdb, указывая ключевое слово COLLATE в условии ORDER BY.

Эти функции указываются в файле конфигурации с помощью параметра Collation = tag@l.nosp@m.ibra.nosp@m.ry.so, где library.so — имя динамической библиотеки с кодом функции (абсолютный путь или имя файла, который находится в одном из каталогов, указанных в переменной окружения LD_LIBRARY_PATH), а tag — имя структуры struct qdb_collation, которая описывает сортировку. Эти объекты определяются следующим образом:

static int mysort( void *arg, int l1, const void *s1, int l2, const void *s2 )
{
return (0);
}
struct qdb_collation ctag = { "nosort",
SQLITE_UTF8,
NULL,
mysort,
NULL };

Здесь ctag — тег, nosort — имя сортировки, которое распознается SQL, а mysort() — вызываемая функция, которая передается в третьем поле (в данном примере NULL) в качестве аргумента arg (подробнее см. в описании функции sqlite3_create_collation()).


Note: Здесь имя ctag использовалось для иллюстрации; вместо него целесообразнее использовать имя nosort, которое совпадает с именем SQL.

В файле конфигурации можно определять несколько процедур сортировки, которые находятся в одной или нескольких динамических библиотеках; каждой процедуре должна соответствовать одна запись Collation= в файле конфигурации соответствующей базы данных, а также структура struct qdb_collation, которая описывает ее и имеет уникальное имя. Этот синтаксис заменяет прежний механизм, в котором использовался массив типа qdb_collmodule_list_t с обязательным именем init_coll_list.

Если в настройках сортировки значение setup не равно NULL, эта функция вызывается при запуске с аргументом data, равным NULL, и аргументом nbytes, равным 0. При последующих вызовах функции qdb_collation() в функцию setup передаются новые данные.

Если процедура сортировки не поддерживает динамическую настройку, можно присвоить значение NULL полю setup структуры struct qdb_collation.

Example

Ниже приведен пример алгоритма сортировки, в котором сортируемая таблица задается указателем arg. Из этого алгоритма в динамическую библиотеку экспортируется следующий код:

uca_t _en_US_ = { ... };
uca_t _fr_FR_ = { ... };
int UCAsort( void *arg, int l1, const void *s1, int l2, const void *s2 )
{
...
}
struct qdb_collation en_US = { "en_US",
SQLITE_UTF8,
&_en_US_,
UCAsort,
NULL };
struct qdb_collation fr_FR = { "fr_FR",
SQLITE_UTF8,
&_fr_FR_,
UCAsort,
NULL };

Обе процедуры сортировки вызывают функцию UCASort(), но передают в нее разные указатели на данные (&_en_US_ и &_fr_FR_). Эти указатели ссылаются на таблицы в динамической библиотеке, которые определяют порядок сортировки английского и французского текста. Они передаются в первый аргумент функции — arg.

Указанные процедуры сортировки необходимо зарегистрировать в файле конфигурации:

[DB]
Collation = en_US@/usr/lib/libqdb_uca.so
Collation = fr_FR@/usr/lib/libqdb_uca.so

sqlite C/C++ API

В этой сокращенной версии документации API C/C++ для sqlite рассматриваются только функции API, к которым можно обращаться в пользовательских функциях.


Note: При изучении документации sqlite следует проверять, что она относится к версии, используемой в ЗОСРВ «Нейтрино».

sqlite3_result_*

void sqlite3_result_blob( sqlite3_context *, const void *, int n, void(*)(void *) );
void sqlite3_result_double( sqlite3_context *, double );
void sqlite3_result_error( sqlite3_context *, const char *, int );
void sqlite3_result_error16( sqlite3_context *, const void *, int );
void sqlite3_result_int( sqlite3_context *, int );
void sqlite3_result_int64( sqlite3_context *, long long int );
void sqlite3_result_null( sqlite3_context * );
void sqlite3_result_text( sqlite3_context *, const char *, int n, void(*)(void *) );
void sqlite3_result_text16( sqlite3_context *, const void *, int n, void(*)(void *) );
void sqlite3_result_text16be( sqlite3_context *, const void *, int n, void(*)(void *) );
void sqlite3_result_text16le( sqlite3_context *, const void *, int n, void(*)(void *) );
void sqlite3_result_value( sqlite3_context *, sqlite3_value * );

Эти процедуры задают возвращаемые значения пользовательских функций. Процедура sqlite3_result_value() возвращает в функцию точную копию одного из своих аргументов.

Пользовательская функция должна передавать в первый аргумент контекст sqlite3_context, полученный от QDB.

sqlite3_value_*

const void * sqlite3_value_blob( sqlite3_value * );
int sqlite3_value_bytes( sqlite3_value * );
int sqlite3_value_bytes16( sqlite3_value * );
double sqlite3_value_double( sqlite3_value * );
int sqlite3_value_int( sqlite3_value * );
long long int sqlite3_value_int64( sqlite3_value * );
const unsigned char * sqlite3_value_text( sqlite3_value * );
const void * sqlite3_value_text16( sqlite3_value * );
const void * sqlite3_value_text16be( sqlite3_value * );
const void * sqlite3_value_text16le( sqlite3_value * );
int sqlite3_value_type( sqlite3_value * );

Эта группа процедур возвращает данные об аргументах пользовательской функции. С помощью этих процедур пользовательские функции получают доступ к своим аргументам.

Процедура sqlite3_value_type() возвращает следующие значения:

SQLITE_INTEGER
SQLITE_FLOAT
SQLITE_TEXT
SQLITE_BLOB
SQLITE_NULL

Если результатом является объект BLOB, функция sqlite3_value_blob() возвращает его размер в байтах. Типы данных не преобразуются. Если результатом является строка (или число, поскольку его можно преобразовать в строку), sqlite3_value_bytes() преобразует ее в строку UTF-8 и возвращает количество байтов в ней без учета завершающего символа \000. Процедура sqlite3_value_bytes16() преобразует значение в кодировку UTF-16 и возвращает количество байтов (не символов) в строке результата без учета завершающего символа \u0000.

При необходимости эти процедуры пытаются преобразовывать значения. Например, если значение имеет внутреннее представление FLOAT, а результатом запроса является текст, функция sprintf() автоматически вызывается и преобразует значение соответствующим образом. Используемые преобразования перечислены в следующей таблице:

Внутренний тип Запрашиваемый тип Преобразование
NULL INTEGER Результат равен 0
NULL FLOAT Результат равен 0.0
NULL TEXT Результатом является указатель NULL
NULL BLOB Результатом является указатель NULL
INTEGER FLOAT Целое число преобразуется в число с плавающей точкой
INTEGER TEXT Целое число представляется в формате ASCII
INTEGER BLOB Аналогично преобразованию INTEGER в TEXT
FLOAT INTEGER Число с плавающей точкой преобразуется в целое число
FLOAT TEXT Число с плавающей точкой представляется в формате ASCII
FLOAT BLOB Аналогично преобразованию FLOAT в TEXT
TEXT INTEGER Вызывается функция atoi()
TEXT FLOAT Вызывается функция atof()
TEXT BLOB Не изменяется
BLOB INTEGER Преобразуется в TEXT с последующим вызовом atoi()
BLOB FLOAT Преобразуется в TEXT с последующим вызовом atof()
BLOB TEXT При необходимости добавляется завершающий символ \000

sqlite3_user_data

void * sqlite3_user_data( sqlite3_context * );

С помощью этого вызова функция может считывать поле arg структуры struct qdb_function, которое используется для регистрации пользовательских функций.




Предыдущий раздел: перейти