Расширение возможностей
Создание функций
В программу MySQL можно добавить новые функции, которые будут использоваться точно так же, как и встроенные функции. Существуют два способа создания таких функций. Первый — это включение функции непосредственно в исходный код MySQL, второй — определение функции в формате UDF (User Definable Function — пользовательская функция). Второй способ подходит, когда функцию требуется хранить и отлаживать отдельно от утилит MySQL. Код функции компилируется в виде библиотечного модуля, который загружается с помощью инструкции CREATE FUNCTION. Первый способ менее удобен, поскольку приходится останавливать сервер и заменять его исполняемый файл. Так обычно поступают с функциями, которые планируется сделать частью проекта MySQL. Ниже будет рассмотрен второй подход.
В дистрибутив MySQL входит пример UDF-функций Он находится в файле sql/udf example.cc. В этом файле содержатся определения шести функций. Я скопировал из него строку, используемую утилитой make для правильного вызова компилятора языка С. В комментариях к файлу рекомендуется выполнить команду make udf example.cc, чтобы посмотреть параметры компиляции статического объектного файла, а затем заменить аргумент – с аргументом – shared – о udf example. so. В листинге 13.5 показана строка компиляции файла в моей системе RedHat в каталоге sql программы MySQL.
c++ \ -DMYSQL SERVER \ -DDEFAUT MYSQL HOME="\"/usr/local\"" \ -DDATADIR="\"/usr/local/share/var\"" \ -DSHAREDIR="\"/usr/local/share/mysql\"" \ -DHAVE CONFIG H \ -DDBUG OFF \ -I../bdb/build unix \ -I../innobase/include \ -I./../include \ -I./../regex \ -I. \ -I../include \ -I.. \ -03 \ -fno-implicit-templates \ -shared \ -o udf example.ccЛистинг 13.5.
После компиляции совместно используемой библиотеки нужно скопировать ее в один из каталогов, перечисленных в /etc/ld.so.conf файле. Если каталог будет другим, укажите его имя в переменной среды LD LIBRARY PATH.
Для активизации функции нужно выполнить инструкцию CREATE FUNCTION. В листинге 13.6 демонстрируется загрузка функций METAPHON и AVGCOST из библиотеки udf example. В результате в таблице mysql.func будут созданы две новые записи, и пока инструкция DROP FUNCTION их не удалит, функции останутся доступны всем пользователям даже в случае перезапуска сервера.
CREATE FUNCTION METAPHON RETURNS STRING SONAME "udf example.so"; CREATE AGGREGATE FUNCTION AVGCOST RETURNS REAL SONAME "udf example.so";Листинг 13.6.
В библиотечном файле может содержаться одна или несколько функций. Язык реализации — С или C++. Каждой SQL-функции в этом файле соответствует как минимум одна функция с аналогичным именем. Кроме того, могут быть созданы функции с суффиксами init и deinit. Например, в файле udf example.сс содержатся определения функций metaphon (), metaphon init () и metaphon deinit (). Когда вводится инструкция, содержащая вызов, сначала происходит обращение к функции с суффиксом init. Затем для каждой записи выполняется основная функция. В конце вызывается функция с суффиксом deinit. Все три функции должны быть безопасны для потоков. Это означает, что в них нельзя использовать глобальные переменные, меняющие свои значения. Функция с суффиксом _init предназначена для динамического выделения памяти, а функция с суфиксом - deinit освобождает выделенную память.
Основная функция может возвращать значение с плавающей запятой, целое число или строку. В первом случае тип результата должен быть double, во втором — long, a в третьем — char *. В листинге 13.7 показано несколько прототипов функций.
Char *metaphon( UDF INIT *initid, UDF ARGS *args, char *result, unsigned long *length, char *is null, char *error); long long sequence( UDF INIT *initid, UDF ARGS *args char *is null, char *error); double myfunc double( UDF INIT *initid, UDF ARGS *args char *is null, char *error); my bool metaphon init( UDF INIT *initid, UDF ARGS *args char *message); void metaphon deinit( UDF INIT *initid);Листинг 13.7.
Числовые значения возвращаются непосредственно, а строковые — через указатели. Программа MySQL резервирует 255 — символьный буфер для аргумента result. В аргументе length должен быть указан размер возвращаемого значения. Если размер превышает 255 байтов, нужно создать собственный буфер в инициализирующей функции и передать указатель на него в поле ptr структуры UDF_INIT. Описание полей структуры приведено в табл. 13.4.
Поле | Описание |
---|---|
my bool maybe null | Указывает на то, может ли функция возвращать пустое значение. Если один из аргументов функции может быть пустым, в это поле будет записана единица |
unsigned int decimals | Содержит количество цифр после запятой, если функция возвращает числовое значение. Будет указана максимальная точность среди всех аргументов |
unsigned int max length | Определяет максимальную длину возвращаемой строки |
char *ptr | С помощью этого указателя осуществляется обмен данными между инициализирующей функцией и другими двумя функциями. Например, можно выделить блок памяти и записать сюда адрес этого блока |
Если функция возвращает пустое значение, аргумент is_null должен быть равен 1. В случае ошибки в аргумент error записывается значение 1. В результате текущая запись и все последующие станут пустыми.
Описание структуры UDF_ARGS приведено в табл. 13.5. Через эту структуру программа MySQL передает аргументы функции.
Создание процедур
Процедуры MySQL выполняют операции над результатами запросов. Процедура активизируется при наличии в конце инструкции SELECT ключевого слова PROCEDURE. В настоящий момент в MySQL входит единственная процедура analyse(). Разрешается создавать собственные процедуры, включая их в программу на этапе компиляции.
Процедуры появились в MySQL версии 3.21, но пока что не вызвали особого энтузиазма. Писать их оказалось слишком сложно для большинства пользователей. Например, для создания процедуры на C++ требуется определить класс, производный от класса Procedure. Код последнего находится в файлах sql / procedure.h и sql / procedure c.c. Процедура analyse реализована в файле sql/sql_analyse_c.c.
С другой стороны можно воспользоваться библиотекой mylua (www.fastflow.it/ mylua) которая позволяет динамически загружать процедуры, написанные на языке LUA (www.lua.org). Для запуска сценария LUA в MySQL нужно вызвать функцию LUA() указав ей имя исходного файла, где содержится определение процедуры.