Для того чтобы работал механизм UDF, функции должны быть написаны на C
или на C++, а используемая операционная система должна поддерживать
динамическую загрузку. В поставку исходного кода входит файл
sql/udf_example.cc, в котором определены пять новых функций. К этому файлу
следует обращаться, если нужно узнать, как работает соглашение о вызовах
UDF.
Чтобы mysqld имел возможность использовать UDF-функции, необходимо
сконфигурировать MySQL с --with-mysqld-ldflags=-rdynamic. Причина здесь в
том, что на многих платформах (включая Linux) можно загружать динамическую
библиотеку (посредством dlopen()) из статически скомпонованной программы,
получаемой при использовании --with-mysqld-ldflags=-all-static. Если есть
потребность использовать UDF, которой нужно обращаться к символам из
mysqld (как в примере функции methaphone из sql/udf_example.cc, которая
использует default_charset_info), то программу необходимо компоновать с
-rdynamic (обращайтесь к man dlopen).
Для каждой функции, которую предполагается использовать в командах SQL,
следует определять соответствующие функции C (или C++). В дальнейшем в
качестве имени для примера функции мы будем использовать имя xxx. Чтобы
различать применение в SQL и C/C++, для вызова SQL-функции мы будем
использовать обозначение XXX() (прописными), а xxx() (строчными) - для
вызова функции C/C++.
Для реализации интерфейса для XXX() требуются следующие функции C/C++:
-
xxx()(обязательная)Главная функция. Она вычисляет результат функции. Соответствие между типами SQL и возвращаемым типом функции C/C++ показано в приведенной ниже таблице:
Тип SQL Тип C/C++ STRINGchar *INTEGERlong longREALdouble -
xxx_init()(необязательная)Функция инициализации для
xxx(). Может быть использована:для проверки количества аргументов к
XXX();для проверки того, что аргументы имеют требуемый тип или, в противном случае, для указания MySQL приводить аргументы к нужным типам при вызове главной функции;
для распределения всей памяти, требуемой основной функцией;
для задания максимальной длины результата;
для задания (для REAL-функций) максимального числа десятичных знаков после запятой;
для указания, может ли результатом быть NULL.
-
xxx_deinit()(необязательная)Функция деинициализации для
xxx(). Должна освобождать всю память, выделенную функцией инициализации.
При запуске SQL-команды XXX() MySQL вызывает функцию инициализации
xxx_init(), чтобы дать ей возможность выполнить все необходимые установки,
такие как проверка аргументов и распределение памяти. Если xxx_init()
возвращает ошибку, то выполнение SQL-команды прерывается с сообщением об
ошибке, а главная функция и функция деинициализации не вызываются. В
противном случае для каждой строки вызывается главная функция xxx(). После
того как будут обработаны все строки, вызывается функция деинициализации
xxx_deinit(), чтобы выполнить необходимую очистку.
Для агрегатных функций (подобных SUM()) необходимо также подготовить
следующие функции:
-
xxx_reset()(обязательная)Сбрасывает сумму и обрабатывает аргумент как начальное значение для новой группы.
-
xxx_add()(обязательная)Добавляет аргумент к имеющейся сумме.
При использовании агрегатных UDF-функций MySQL работает следующим образом:
Вызывается
xxx_init(), чтобы агрегатная функция могла распределить память, которая понадобится для хранения результатов.Таблица сортируется в соответствии с выражением
GROUP BY.Для первой строки новой группы вызывается функция
xxx_reset().Для каждой новой строки, принадлежащей к той же группе, вызывается функция
xxx_add().Когда группа меняется, или после завершения обработки последней строки вызывается
xxx()для получения итога.Повторяются шаги 3-5, пока не будут обработаны все строки.
Вызывается
xxx_deinit(), чтобы UDF могла освободить всю распределенную ею память.
Все функции должны поддерживать многопоточность (не только главная, но
также и функции инициализации и деинициализации). Это означает, что
непозволительно распределять какие-либо глобальные или статические
переменные с изменяющимися значениями! Если требуется память, то ее
следует распределять в xxx_init() и освобождать в xxx_deinit().