Создание собственных SQL-функций и функций сортировки
В этой статье:
В QDB существуют два типа пользовательских функций: к первому типу относятся скалярные или агрегирующие функции, которые преобразуют данные, а ко второму типу — функции сортировки, которые упорядочивают данные. Скалярные функции вызываются с помощью SQL-оператора SELECT, а процедуры сортировки — с помощью условия COLLATE. ABS() является примером встроенной скалярной функции, а BINARY() —встроенной функции сортировки.
Чтобы предоставить службе QDB доступ к пользовательским функциям, необходимо скомпилировать их в динамическую библиотеку, а затем дать QDB команду загрузить ее, указав параметры Collation или Function для каждой функции в файле конфигурации базы данных.
Эти функции указываются в файле конфигурации с помощью параметра Function = tag@l, где library.so — имя динамической библиотеки с кодом функции (абсолютный путь или имя файла, который находится в одном из каталогов, указанных в переменной окружения LD_LIBRARY_PATH), а tag — имя структуры ibra ry.sostruct 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().
![]() | Здесь имя ftag использовалось для иллюстрации; вместо него целесообразнее использовать имя func, которое совпадает с именем SQL. |
В файле конфигурации можно определять несколько функций, которые находятся в одной или нескольких динамических библиотеках; каждой функции должна соответствовать одна запись Function= в файле конфигурации соответствующей базы данных, а также структура struct qdb_function с уникальным именем, которая описывает функцию.
Функции сортировки упорядочивают результаты оператора SQL: SELECT. Разработчик может определять собственные функции сортировки и выполнять их с помощью службы qdb, указывая ключевое слово COLLATE в условии ORDER BY.
Эти функции указываются в файле конфигурации с помощью параметра Collation = tag@l, где library.so — имя динамической библиотеки с кодом функции (абсолютный путь или имя файла, который находится в одном из каталогов, указанных в переменной окружения LD_LIBRARY_PATH), а tag — имя структуры ibra ry.sostruct 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()).
![]() | Здесь имя 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.
Ниже приведен пример алгоритма сортировки, в котором сортируемая таблица задается указателем 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.soCollation = fr_FR@/usr/lib/libqdb_uca.so
В этой сокращенной версии документации API C/C++ для sqlite рассматриваются только функции API, к которым можно обращаться в пользовательских функциях.
![]() | При изучении документации sqlite следует проверять, что она относится к версии, используемой в ЗОСРВ «Нейтрино». |
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.
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() возвращает следующие значения:
Если результатом является объект 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 |
void * sqlite3_user_data( sqlite3_context * );
С помощью этого вызова функция может считывать поле arg структуры struct qdb_function, которое используется для регистрации пользовательских функций.
Предыдущий раздел: перейти