Опубликован: 16.04.2007 | Доступ: свободный | Студентов: 5325 / 859 | Оценка: 4.18 / 4.08 | Длительность: 16:03:00
Лекция 13:

Расширение возможностей

< Лекция 12 || Лекция 13: 123

Создание функций

В программу 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.

Таблица 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 передает аргументы функции.

Таблица 13.5.
unsigned int arg_count Содержит число аргументов функции. Если это значение фиксировано, проверьте его в инициализирующей функции
enum Item_result *arg_type Содержит массив типов аргументов. Возможные значения массива таковы: INT_RESULT, REAL RESULT и STRING RESULT. Можно осуществлять проверку типов и в случае несовпадения либо возвращать признак ошибки, либо корректировать содержимое массива, приводя аргументы к нужному типу
char **args Содержит массив значений аргументов. Если аргумент является строкой, в массиве будет храниться указатель на строку. Длины строковых аргументов приведены в массиве lengths. Если аргумент представляет собой целое число или число с плавающей запятой, приведите значение к типу long или double соответственно
unsigned long *lengths Содержит массив длин аргументов. В инициализирующей функции эти значения устанавливаются по максимуму на основании определений столбцов. В основной функции длины строковых аргументов являются точными

Создание процедур

Процедуры 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() указав ей имя исходного файла, где содержится определение процедуры.

< Лекция 12 || Лекция 13: 123
Александра Каева
Александра Каева
Дмитрий Черепенин
Дмитрий Черепенин

Какого года данный курс?