Mysql функции описание и примеры. Хранимые процедуры и триггеры

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

Практическая работа

Функции в MySQL

Задание 1. Встроенные функции

математический функция программирование

Функции - это операции, позволяющие манипулировать данными. В MySQL можно выделить несколько групп встроенных функций:

Строковые функции . Используются для управления текстовыми строками, например, для обрезания или заполнения значений.

Числовые функции . Используются для выполнения математических операций над числовыми данными. К числовым функциям относятся функции возвращающие абсолютные значения, синусы и косинусы углов, квадратный корень числа и т.д. Используются они только для алгебраических, тригонометрических и геометрических вычислений. В общем, используются редко, поэтому рассматривать их мы не будем. Но вы должны знать, что они существуют, и в случае необходимости обратиться к документации MySQL.

Итоговые функции . Используются для получения итоговых данных по таблицам, например, когда надо просуммировать какие-либо данные без их выборки.

Функции даты и времени . Используются для управления значениями даты и времени, например, для возвращения разницы между датами.

Системные функции . Возвращают служебную информацию СУБД.

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

Давайте в качестве примера рассмотрим интернет-магазин.

Концептуальная модель:

Реляционная модель:

Итак, смотрим на последнюю схему и создаем БД - shop.

create database shop;

Выбираем ее для работы:

И создаем в ней 8 таблиц, как в схеме: Покупатели (customers), Поставщики (vendors), Покупки (sale), Поставки (incoming), Журнал покупок (magazine_sales), Журнал поставок (magazine_incoming), Товары (products), Цены (prices). Один нюанс, наш магазин будет торговать книгами, поэтому в таблицу Товары мы добавим еще один столбец - Автор (author), в принципе это необязательно, но так как-то привычнее.

Обратите внимание, что в таблицах Журнал покупок, Журнал поставок и Цены первичные ключи - составные, т.е. их уникальные значения состоят из пар значений (в таблице не может быть двух строк с одинаковыми парами значений). Названия столбцов этих пар значений и указываются через запятую после ключевого слова PRIMARY KEY.

В настоящем интернет-магазине данные в эти таблицы будут заноситься посредством сценариев на каком-либо языке (типа php), нам же пока придется внести их вручную. Можете внести любые данные, только помните, что значения в одноименных столбцах связанных таблиц должны совпадать. Либо скопируйте нижеприведенные данные:

Итак, в нашем магазине 24 наименования товара, привезенные в трех поставках от трех поставщиков, и совершенно три продажи. Все готово, можем приступать к изучению встроенных функций MySQL.

Задание 2 . Итоговые функции, вычисляемые столбцы и представления

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

AVG() Функция возвращает среднее значение столбца.

COUNT() Функция возвращает число строк в столбце.

MAX() Функция возвращает самое большое значение в столбце.

MIN() Функция возвращает самое маленькое значение в столбце.

SUM() Функция возвращает сумму значений столбца.

С одной из них - COUNT() - мы уже познакомилисьhttp://www.site-do.ru/db/sql8.php. Сейчас познакомимся с остальными. Предположим, мы захотели узнать минимальную, максимальную и среднюю цену на книги в нашем магазине. Тогда из таблицы Цены (prices) надо взять минимальное, максимальное и среднее значения по столбцу price. Запрос простой:

SELECT MIN(price), MAX(price), AVG(price) FROM prices;

Теперь, мы хотим узнать, на какую сумму нам привез товар поставщик "Дом печати" (id=2). Составить такой запрос не так просто. Давайте поразмышляем, как его составить:

Сначала надо из таблицы Поставки (incoming) выбрать идентификаторы (id_incoming) тех поставок, которые осуществлялись поставщиком "Дом печати" (id=2):

Теперь из таблицы Журнал поставок (magazine_incoming) надо выбрать товары (id_product) и их количества (quantity), которые осуществлялись в найденных в пункте 1 поставках. То есть запрос из пункта 1 становится вложенным:

Теперь нам надо добавить в результирующую таблицу цены на найденные товары, которые хранятся в таблице Цены (prices). То есть нам понадобится объединение таблиц Журнал поставок (magazine_incoming) и Цены (prices) по столбцу id_product:

В получившейся таблице явно не хватает столбца Сумма, то есть вычисляемого столбца. Возможность создания таких столбцов предусмотрена в MySQL. Для этого надо лишь указать в запросе имя вычисляемого столбца и что он должен вычислять. В нашем примере такой столбец будет называться summa, а вычислять он будет произведение столбцов quantity и price. Название нового столбца отделяется словом AS:

Отлично, нам осталось лишь просуммировать столбец summa и наконец-то узнаем, на какую сумму нам привез товар поставщик "Дом печати". Синтаксис для использования функции SUM() следущий:

SELECT SUM(имя_столбца) FROM имя_таблицы;

Имя столбца нам известно - summa, а вот имени таблицы у нас нет, так как она является результатом запроса. Что же делать? Для таких случаев в MySQL существуют Представления. Представление - это запрос на выборку, которому присваивается уникальное имя и который можно сохранять в базе данных, для последующего использования.

Синтаксис создания представления следующий:

CREATE VIEW имя_представления AS запрос;

Давайте сохраним наш запрос, как представление с именем report_vendor:

CREATE VIEW report_vendor AS

SELECT magazine_incoming.id_product, magazine_incoming.quantity, prices.price,

magazine_incoming.quantity*prices.price AS summa

FROM magazine_incoming, prices

WHERE magazine_incoming.id_product= prices.id_product AND id_incoming=

Вот теперь можно использовать итоговую функцию SUM():

Вот мы и достигли результата, правда для этого нам пришлось использовать вложенные запросы, объединения, вычисляемые столбцы и представления. Да, иногда для получения результата приходится подумать, без этого никуда. Зато мы коснулись двух очень важных тем - вычисляемые столбцы и представления. Давайте поговорим о них поподробнее.

Вычисляемые поля (столбцы)

На примере мы рассмотрели математическое вычисляемое поле. Здесь хотелось бы добавить, что использовать можно не только операцию умножения (*), но и вычитание (-), и сложение (+), и деление (/). Синтаксис следующий:

SELECT имя_столбца_1, имя_столбца_2, имя_столбца_1*имя_столбца_2 AS имя_вычисляемого_столбца

FROM имя_таблицы;

Второй нюанс - ключевое слово AS, мы его использовали для задания имени вычисляемого столбца. На самом деле с помощью этого ключевого слова задаются псевдонимы для любых столбцов. Зачем это нужно? Для сокращения и читаемости кода. Например, наше представление могло бы выглядеть так:

CREATE VIEW report_vendor AS

SELECT A.id_product, A.quantity, B.price, A.quantity*B.price AS summa

FROM magazine_incoming AS A, prices AS B

WHERE A.id_product= B.id_product AND id_incoming=

(SELECT id_incoming FROM incoming WHERE id_vendor=2);

Согласитесь, что так гораздо короче и понятнее.

Представления

Синтаксис создания представлений мы уже рассматривали. После создания представлений, их можно использовать так же, как таблицы. То есть выполнять запросы к ним, фильтровать и сортировать данные, объединять одни представления с другими. С одной стороны это очень удобный способ хранения частоприменяемых сложных запросов (как в нашем примере).

Но следует помнить, что представления - это не таблицы, то есть они не хранят данные, а лишь извлекают их из других таблиц. Отсюда, во-первых, при изменении данных в таблицах, результаты представления так же будут меняться. А во-вторых, при запросе к представлению происходит поиск необходимых данных, то есть производительность СУБД снижается. Поэтому злоупотреблять ими не стоит.

Строковые функции Sql

Эта группа функций позволяет манипулировать текстом. Строковых функций много, мы рассмотрим наиболее употребительные.

CONCAT(str1,str2...)

Возвращает строку, созданную путем объединения аргументов (аргументы указываются в скобках - str1,str2...). Например, в нашей таблице Поставщики (vendors) есть столбец Город (city) и столбец Адрес (address). Предположим, мы хотим, чтобы в результирующей таблице Адрес и Город указывались в одном столбце, т.е. мы хотим объединить данные из двух столбцов в один. Для этого мы будем использовать строковую функцию CONCAT(), а в качестве аргументов укажем названия объединяемых столбцов - city и address:

Обратите внимание, объединение произошло без разделения, что не очень читабельно. Давайте подправим наш запрос, чтобы между объединяемыми столбцами был пробел:

Как видите, пробел считается тоже аргументом и указывается через запятую. Если объединяемых столбцов было бы больше, то указывать каждый раз пробелы было бы нерационально. В этом случае можно было бы использовать строковую функцию CONCAT_WS(разделитель, str1,str2...), которая помещает разделитель между объединяемыми строками (разделитель указывается, как первый аргумент). Наш запрос тогда будет выглядеть так:

SELECT CONCAT_WS(" ", city, address) FROM vendors;

Результат внешне не изменился, но если бы мы объединяли 3 или 4 столбца, то код значительно бы сократился.

INSERT(str, pos, len, new_str)

Возвращает строку str, в которой подстрока, начинающаяся с позиции pos и имеющая длину len символов, заменена подстрокой new_str. Предположим, мы решили в столбце Адрес (address) не отображать первые 3 символа (сокращения ул., пр., и т.д.), тогда мы заменим их на пробелы:

То есть три символа, начиная с первого, заменены тремя пробелами.

LPAD(str, len, dop_str) Возвращает строку str, дополненную слева строкой dop_str до длины len. Предположим, мы хотим, чтобы при выводе городов поставщиков они располагались бы справа, а пустое пространство заполнялось бы точками:

RPAD(str, len, dop_str)

Возвращает строку str, дополненную справа строкой dop_str до длины len. Предположим, мы хотим, чтобы при выводе городов поставщиков они располагались бы слева, а пустое пространство заполнялось бы точками:

Обратите внимание, значение len ограничивает количество выводимых символов, т.е. если название города будет длиннее 15 символов, то оно будет обрезано.

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

SELECT LTRIM(city) FROM vendors;

Возвращает строку str, в которой удалены все конечные пробелы:

SELECT RTRIM(city) FROM vendors;

В нашем случае лишних пробелов не было, поэтому и результат внешне мы не увидим.

Возвращает строку str, в которой удалены все начальные и конечные пробелы:

SELECT TRIM(city) FROM vendors;

Возвращает строку str, в которой все символы переведены в нижний регистр. С русскими буквами работает некорректно, поэтому лучше не применять. Например, давайте применим эту функцию к столбцу city:

Видите, какая абракадабра получилась. А вот с латиницей все в порядке:

Возвращает строку str, в которой все символы переведены в верхний регистр. С русскими буквами так же лучше не применять. А вот с латиницей все в порядке:

Возвращает длину строки str. Например, давайте узнаем сколько символов в наших адресах поставщиков:

Возвращает len левых символов строки str. Например, пусть в городах поставщиков выводится только первые три символа:

Возвращает len правых символов строки str. Например, пусть в городах поставщиков выводится только последние три символа:

Возвращает строку str n-количество раз. Например:

REPLACE(str, pod_str1, pod_str2)

Возвращает строку str, в которой все подстроки pod_str1 заменены подстроками pod_str2. Например, пусть мы хотим, чтобы в городах поставщиков вместо длинного "Санкт-Петербург" выводилось короткое "СПб":

Возвращает строку str, записанную в обратном порядке:

LOAD_FILE(file_name)

Эта функция читает файл file_name и возвращает его содержимое в виде строки. Например, создайте файл proverka.txt, напишите в нем какой-нибудь текст (лучше латиницей, чтобы не было проблем с кодировками), сохраните его на диске С и сделайте следующий запрос:

Обратите внимание, необходимо указывать абсолютный путь к файлу.

Как уже упоминалось строковых функций гораздо больше, но даже некоторые рассмотренные здесь применяются крайне редко. Поэтому на этом закончим их рассмотрение и перейдем к более используемым функциям даты и времени.

Задание 3 . Функции даты и времени

Эти функции предназначены для работы с календарными типами данных. Рассмотрим наиболее применимые.

CURDATE(), CURTIME() и NOW()

Первая функция возвращает текущую дату, вторая - текущее время, а третья - текущую дату и время. Сравните:

Функции CURDATE() и NOW() удобно использовать для добавления в базу данных записей, использующих текущее время. В нашем магазине все поставки и продажи используют текущее время. Поэтому для добавления записей о поставах, и продажах удобно использовать функцию CURDATE(). Например, пусть в наш магазин пришел товар, давайте добавим информацию об этом в таблицу Поставка (incoming):

Если бы мы хранили дату поставки с типом datatime, то нам больше подошла бы функция NOW().

ADDDATE(date, INTERVAL value) Функция возвращает дату date, к которой прибавлено значение value. Значение value может быть отрицательным, тогда итоговая дата уменьшится. Давайте посмотрим, когда наши поставщики делали поставки товара:

Предположим, мы ошиблись при вводе даты для первого поставщика, давайте уменьшим его дату на одни сутки:

В качестве значения value могут выступать не только дни, но и недели (WEEK), месяцы (MONTH), кварталы (QUARTER) и годы (YEAR). Давайте для пример уменьшим дату поставки для второго поставщика на 1 неделю:

В нашей таблице Поставки (incoming) мы использовали для столбца Дата поставки (date_incoming) тип date. Этот тип данных предназначен для хранения только даты. А вот если бы мы использовали тип datatime, то у нас отображалась бы не только дата, но и время. Тогда мы могли бы использовать функцию ADDDATE и для времени. В качестве значения value в этом случае могут выступать секунды (SECOND), минуты (MINUTE), часы (HOUR) и их комбинации:

минуты и секунды (MINUTE_SECOND),

часы, минуты и секунды (HOUR_SECOND),

часы и минуты (HOUR_MINUTE),

дни, часы, минуты и секунды (DAY_SECOND),

дни, часы и минуты (DAY_MINUTE),

дни и часы (DAY_HOUR),

года и месяцы (YEAR_MONTH).

SUBDATE(date, INTERVAL value)

функция идентична предыдущей, но производит операцию вычитания, а не сложения.

PERIOD_ADD(period, n)

функция добавляет n месяцев к значению даты period. Нюанс: значение даты должно быть представлено в формате YYYYMM. Давайте к февралю 2011 (201102) прибавим 2 месяца:

TIMESTAMPADD(interval, n, date)

функция добавляет к дате date временной интервал n, значения которого задаются параметром interval. Возможные значения параметра interval:

FRAC_SECOND - микросекунды

SECOND - секунды

MINUTE - минуты

WEEK - недели

MONTH - месяцы

QUARTER - кварталы

TIMEDIFF(date1, date2)

вычисляет разницу в часах, минутах и секундах между двумя датами.

DATEDIFF(date1, date2)

вычисляет разницу в днях между двумя датами. Например, мы хотим узнать, как давно поставщик "Вильямс" (id=1) поставлял нам товар:

PERIOD_DIFF(period1, period2)

функция вычисляет разницу в месяцах между двумя датами, представленными в формате YYYYMM. Давайте узнаем разницу между январем 2010 и августом 2011:

TIMESTAMPDIFF(interval, date1, date2)

функция вычисляет разницу между датами date2 и date1 в единицах, указанных в параметре interval. Возможные значения параметра interval:

FRAC_SECOND - микросекунды

SECOND - секунды

MINUTE - минуты

WEEK - недели

MONTH - месяцы

QUARTER - кварталы

SUBTIME(date, time)

функция вычитает из времени date время time:

возвращает дату, отсекая время. Например:

возвращает время, отсекая дату. Например:

функция принимает дату date и возвращает полный вариант со временем. Например:

DAY(date) и DAYOFMONTH(date)

функции-синонимы, возвращают из даты порядковый номер дня месяца:

DAYNAME(date), DAYOFWEEK(date) и WEEKDAY(date)

функции возвращают день недели, первая - его название, вторая - номер дня недели (отсчет от 1 - воскресенье до 7 - суббота), третья - номер дня недели (отсчет от 0 - понедельник, до 6 - воскресенье:

WEEK(date), WEEKOFYEAR(datetime)

обе функции возвращают номер недели в году, первая для типа date, а вторая - для типа datetime, у первой неделя начинается с воскресенья, у второй - с понедельника:

MONTH(date) и MONTHNAME(date)

обе функции возвращают значения месяца. Первая - его числовое значение (от 1 до 12), вторая - название месяца:

функция возвращает значение квартала года (от 1 до 4):

YEAR(date) функция возвращает значение года (от 1000 до 9999):

возвращает порядковый номер дня в году (от 1 до 366):

возвращает значение часа для времени (от 0 до 23):

MINUTE(datetime)

возвращает значение минут для времени (от 0 до 59):

SECOND(datetime)

возвращает значение секунд для времени (от 0 до 59):

EXTRACT(type FROM date)

возвращает часть date определяемую параметром type:

TO_DAYS(date) и FROM_DAYS(n)

взаимообратные функции. Первая преобразует дату в количество дней, прошедших с нулевого года. Вторая, наоборот, принимает число дней, прошедших с нулевого года и преобразует их в дату:

UNIX_TIMESTAMP(date) и FROM_UNIXTIME(n)

взаимообратные функции. Первая преобразует дату в количество секунд, прошедших с 1 января 1970 года. Вторая, наоборот, принимает число секунд, с 1 января 1970 года и преобразует их в дату:

TIME_TO_SEC(time) и SEC_TO_TIME(n)

взаимообратные функции. Первая преобразует время в количество секунд, прошедших от начала суток. Вторая, наоборот, принимает число секунд с начала суток и преобразует их во время:

MAKEDATE(year, n)

функция принимает год и номер дня в году и преобразует их в дату:

Задание 4. Ф ункции форматирования даты и времени

Эти функции также предназначены для работы с календарными типами данных. Рассмотрим их подробнее.

DATE_FORMAT(date, format)

форматирует дату date в соответствии с выбранным форматом formate. Эта функция очень часто используется. Например, в MySQL дата имеет формат представления YYYY-MM-DD (год-месяц-число), а нам привычнее формат DD-MM-YYYY (число-месяц-год). Поэтому для привычного нам отображения даты ее необходимо переформатировать. Давайте сначала приведем запрос, а затем разберемся, как задавать формат:

Теперь дата выглядит для нас привычно. Для задания формата даты используются специальные определители. Для удобства перечислим их в таблице.

Описание

Сокращенное наименование дня недели (Mon - понедельник, Tue - вторник, Wed - среда, Thu - четверг, Fri - пятница, Sat - суббота, Sun - воскресенье).

Сокращенное наименование месяцев (Jan - январь, Feb - февраль, Mar - март, Apr - апрель, May - май, Jun - июнь, Jul - июль, Aug - август, Sep - сентябрь, Oct - октябрь, Nov - ноябрь, Dec - декабрь).

Месяц в числовой форме (1 - 12).

День месяца в числовой форме с нулем (01 - 31).

День месяца в английском варианте (1st, 2nd...).

День месяца в числовой форме без нуля (1 - 31).

Часы с ведущим нулем от 00 до 23.

Часы с ведущим нулем от 00 до 12.

Минуты от 00 до 59.

День года от 001 до 366.

Часы c ведущим нулем от 0 до 23.

Часы без ведущим нуля от 1 до 12.

Название месяца без сокращения.

Месяц в числовой форме с ведущим нулем (01 - 12).

АМ или РМ для 12-часового формата.

Время в 12-часовом формате.

Секунды от 00 до 59.

Время в 24-часовом формате.

Неделя (00 - 52), где первым днем недели считается понедельник.

Неделя (00 - 52), где первым днем недели считается воскресенье.

Название дня недели без сокращения.

Номер дня недели (0 - воскресенье, 6 - суббота).

Год, 4 разряда.

Год, 2 разряда.

STR_TO_DATE(date, format)

функция обратная предыдущей, она принимает дату date в формате format, а возвращает дату в формате MySQL.

.

TIME_FORMAT(time, format)

функция аналогична функции DATE_FORMAT(), но используется только для времени:

GET_FORMAT(date, format)

функция возвращает строку форматирования, соответствующую одному из пяти форматов времени:

EUR - европейский стандарт

USA - американский стандарт

JIS - японский индустриальный стандарт

ISO - стандарт ISO (международная организация стандартов)

INTERNAL - интернациональный стандарт

Эту функцию хорошо использовать совместно с предыдущей -

Посмотрим на примере:

Как видите, сама функция GET_FORMAT() возвращает формат представления, а вместе с функцией DATE_FORMAT() выдает дату в нужном формате. Сделайте сами запросы со всеми пятью стандартами и посмотрите на разницу .

Ну вот, теперь вы знаете о работе с датами и временем в MySQL практически все. Это вам очень пригодится при разработке различных web-приложений. Например, если пользователь в форму на сайте вводит дату в привычном ему формате, вам не составит труда применить нужную функцию, чтобы в БД дата попала в нужном формате.

Задание 5. Хранимые процедуры

Как правило, мы в работе с БД используем одни и те же запросы, либо набор последовательных запросов. Хранимые процедуры позволяют объединить последовательность запросов и сохранить их на сервере. Это очень удобный инструмент, и сейчас вы в этом убедитесь. Начнем с синтаксиса:

CREATE PROCEDURE

имя_процедуры (параметры)

операторы

Параметры это те данные, которые мы будем передавать процедуре при ее вызове, а операторы - это собственно запросы. Давайте напишем свою первую процедуру и убедимся в ее удобстве. Когда мы добавляли новые записи в БД shop, мы использовали стандартный запрос на добавление вида:

INSERT INTO customers (name, email) VALUE ("Иванов Сергей", "[email protected]");

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

CREATE PROCEDURE ins_cust(n CHAR(50), e CHAR(50))

insert into customers (name, email) value (n, e);

Обратите внимание, как задаются параметры: необходимо дать имя параметру и указать его тип, а в теле процедуры мы уже используем имена параметров. Один нюанс. Как вы помните, точка с запятой означает конец запроса и отправляет его на выполнение, что в данном случае неприемлемо. Поэтому, прежде, чем написать процедуру необходимо переопределить разделитель с; на "//", чтобы запрос не отправлялся раньше времени. Делается это с помощью оператора DELIMITER //:

Таким образом, мы указали СУБД, что выполнять команды теперь следует после //. Следует помнить, что переопределение разделителя осуществляется только на один сеанс работы, т.е. при следующем сеансе работы с MySql разделитель снова станет точкой с запятой и при необходимости его придется снова переопределять. Теперь можно разместить процедуру:

Итак, процедура создана. Теперь, когда нам понадобится ввести нового покупателя нам достаточно ее вызвать, указав необходимые параметры. Для вызова хранимой процедуры используется оператор CALL, после которого указывается имя процедуры и ее параметры. Давайте добавим нового покупателя в нашу таблицу Покупатели (customers):

Согласитесь, что так гораздо проще, чем писать каждый раз полный запрос. Проверим, работает ли процедура, посмотрев, появился ли новый покупатель в таблице Покупатели (customers):

Появился, процедура работает, и будет работать всегда, пока мы ее не удалим с помощью оператора DROP PROCEDURE название_процедуры.

Как было сказано в начале задания, процедуры позволяют объединить последовательность запросов. Давайте посмотрим, как это делается. Попробуем узнать, на какую сумму нам привез товар поставщик "Дом печати"? Раньше для этого нам пришлось бы использовать вложенные запросы, объединения, вычисляемые столбцы и представления. А если мы захотим узнать, на какую сумму нам привез товар другой поставщик? Придется составлять новые запросы, объединения и т.д. Проще один раз написать хранимую процедуру для этого действия.

Казалось бы, проще всего взять уже написанные представление и запрос к нему, объединить в хранимую процедуру и сделать идентификатор поставщика (id_vendor) входным параметром, вот так:

Но так процедура работать не будет. Все дело в том, что в представлениях не могут использоваться параметры. Поэтому нам придется несколько изменить последовательность запросов. Сначала мы создадим представление, которое будет выводить идентификатор поставщика (id_vendor), идентификатор продукта (id_product), количество (quantity), цену (price) и сумму (summa) из трех таблиц Поставки (incoming), Журнал поставок (magazine_incoming), Цены (prices):

А потом создадим запрос, который просуммирует суммы поставок интересующего нас поставщика, например, с id_vendor=2:

SELECT SUM(summa) FROM report_vendor WHERE id_vendor=2;

Вот теперь мы можем объединить два этих запроса в хранимую процедуру, где входным параметром будет идентификатор поставщика (id_vendor), который будет подставляться во второй запрос, но не в представление:

Проверим работу процедуры, с разными входными параметрами:

Как видите, процедура срабатывает один раз, а затем выдает ошибку, говоря нам, что представление report_vendor уже имеется в БД. Так происходит потому, что при обращении к процедуре в первый раз, она создает представление. При обращении во второй раз, она снова пытается создать представление, но оно уже есть, поэтому и появляется ошибка. Чтобы избежать этого возможно два варианта.

Первый - вынести представление из процедуры. То есть мы один раз создадим представление, а процедура будет лишь к нему обращаться, но не создавать его. Предварительно не забудет удалить уже созданную процедуру и представление:

Проверяем работу:

call sum_vendor(1)//

call sum_vendor(2)//

call sum_vendor(3)//

Второй вариант - прямо в процедуре дописать команду, которая будет удалять представление, если оно существует:

Перед использованием этого варианта не забудьте удалить процедуру sum_vendor, а затем проверить работу:

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

Задание 6. Хранимые процедуры

Теперь давайте узнаем, как можно посмотреть, какие хранимые процедуры имеются у нас на сервере, и как они выглядят. Для этого познакомимся с двумя операторами:

SHOW PROCEDURE STATUS - позволяет просмотреть список имеющихся хранимых процедур. Правда просматривать этот список не очень удобно, т.к. по каждой процедуре выдается информация об имени БД, к которой процедура принадлежит, ее типе, учетной записи, от имени которой была создана процедура, о дате создания и изменения процедуры и т.д. И все-таки, если вам необходимо посмотреть, какие процедуры у вас есть, то стоит воспользоваться этим оператором.

SHOW CREATE PROCEDURE имя_процедуры - позволяет получить информацию о конкретной процедуре, в частности просмотреть ее код. Вид для просмотра также не очень удобный, но разобраться можно.

Попробуйте оба оператора в действии, чтобы знать, как это выглядит. А теперь рассмотрим более удобный вариант получения подобной информации. В системной базе данных MySQL есть таблица proc, где и хранится информация о процедурах. Так вот мы может сделать SELECT-запрос к этой таблице. Причем, если мы создадим привычный запрос:

SELECT * FROM mysql.proc//

То получим нечто такое же нечитабельное, как и при использовании операторов SHOW. Поэтому мы будем создавать запросы с условиями. Например, если мы создадим вот такой запрос:

SELECT name FROM mysql.proc//

То получим имена всех процедур всех баз данных, имеющихся на сервере. Нас, например, на данный момент интересуют только процедуры базы данных shop, поэтому изменим запрос:

SELECT name FROM mysql.proc WHERE db="shop"//

Вот теперь мы получили то, что хотели:

Если же мы хотим посмотреть только тело конкретной процедуры (т.е. от begin до end), то мы напишем такой запрос:

SELECT body FROM mysql.proc WHERE name="sum_vendor"//

И увидим вполне читабельный вариант:

Вообще, чтобы извлекать из таблицы proc необходимую вам информацию, надо просто знать, какие столбцы она содержит, а для этого можно воспользоваться знакомым нам оператором describe имя_таблицы, в нашем случае describe mysql.proc. Правда, вид у нее тоже не очень читабельный, поэтому приведем здесь названия наиболее востребованных столбцов:

db - имя БД, в которую сохранена процедура.

name - имя процедуры.

param_list - список параметров процедуры.

body - тело процедуры.

comment - комментарий к хранимой процедуре.

Столбцы db, name и body мы уже использовали. Запрос, извлекающий параметры процедуры sum_vendor составьте самостоятельно. А вот про комментарии к хранимым процедурам мы сейчас поговорим подробнее.

Комментарии вещь крайне необходимая, ведь через какое-то время мы может забыть, что делает та или иная процедура. Конечно, по ее коду можно восстановить нашу память, но зачем? Гораздо проще сразу при создании процедуры указать, что она делает, и тогда, даже по прошествии долгого времени, обратившись к комментариям, мы сразу вспомним, зачем эта процедура создавалась.

Создавать комментарии крайне просто. Для этого сразу после списка параметров, но еще до начала тела хранимой процедуры указываем ключевое слово COMMENT "здесь комментарий". Давайте удалим нашу процедуру sum_vendor и создадим новую, с комментарием:

А теперь сделаем запрос к комментарию процедуры:

Вообще-то, чтобы добавить комментарий, вовсе не обязательно было удалять старую процедуру. Можно было отредактировать имеющуюся хранимую процедуру с помощью оператора ALTER PROCEDURE. Давайте посмотрим, как это сделать, на примере процедуры ins_cust из прошлого задания. Эта процедура вводит информацию о новом покупателе в таблицу Покупатели (customers). Давайте добавим комментарий к этой процедуре:

ALTER PROCEDURE ins_cust COMMENT

Вводит информацию о новом покупателе в таблицу Покупатели."//

И сделаем запрос к комментарию, чтобы проверить:

SELECT comment FROM mysql.proc WHERE name="ins_cust"//

В нашей базе данных всего две процедуры, и комментарии к ним кажутся излишними. Не ленитесь, обязательно пишите комментарии. Представьте, что в нашей базе данных десятки или сотни процедур. Сделав нужный запрос, вы без труда узнаете, какие процедуры есть и что они делают и поймете, что комментарии - это не излишества, а экономия вашего времени в будущем. Кстати, а вот и сам запрос:

Ну вот, теперь мы умеем извлекать любую информацию о наших процедурах, что позволит нам ничего не забыть и не запутаться.

Задание 7. Хранимые процедуры

Хранимые процедуры это не просто контейнера для групп запросов, как может показаться. Хранимые процедуры могут в своей работе использовать операторы ветвления. Вне хранимых процедур такие операторы использовать нельзя.

Начнем изучение с операторов IF...THEN...ELSE. Если вы знакомы с каким-нибудь языком программирования, то эта конструкция вам знакома. Напомним, что условный оператор IF позволяет организовать ветвление программы. В случае хранимых процедур этот оператор позволяет выполнять разные запросы, в зависимости от входных параметров. На примере, как всегда, будет понятнее. Но для начала синтаксис:

Логика работы проста: если условие истинно, то выполняется запрос 1, в противном случае - запрос 2.

Предположим, каждый день мы устраиваем в нашем магазине счастливые часы, т.е. делаем скидку 10% на все книги в последний час работы магазина. Чтобы иметь возможность выбирать цену книги, нам необходимо иметь два ее варианта - со скидкой и без. Для этого, нам понадобится создать хранимую процедуру с оператором ветвления. Так как мы имеем всего два варианта цены, то удобнее в качестве входящего параметра иметь булево значение, которое, как вы помните, может принимать либо 0 - ложь, либо 1 - истина. Код процедуры может быть таким:

Т.е. на входе у нас параметр, который может являться, либо 1 (если скидка есть), либо 0 (если скидки нет). В первом случае будет выполнен первый запрос, во втором - второй. Давайте посмотрим, как работает наша процедура в обоих вариантах:

call discount(1)//

call discount(0)//

Оператор IF позволяет выбирать и большее количество вариантов запросов, в таком случае используется следующий синтаксис:

CREATE PROCEDURE имя_процедуры (параметры)

IF(условие) THEN

ELSEIF(условие) THEN

Причем блоков ELSEIF может быть несколько. Предположим, что мы решили делать скидки нашим покупателям в зависимости от суммы покупки, до 1000 рублей скидки нет, от 1000 до 2000 рублей - скидка 10%, более 2000 рублей - скидка 20%. Входным параметром для такой процедуры должна быть сумма покупки. Поэтому сначала нам надо написать процедуру, которая будет ее подсчитывать. Сделаем это по аналогии с процедурой sum_vendor, созданной в уроке 15, которая подсчитывала сумму товара по идентификатору поставщика.

Необходимые нам данные хранятся в двух таблицах Журнал покупок (magazine_sales) и Цены (prices).

CREATE PROCEDURE sum_sale(IN i INT)

COMMENT "Возвращает сумму покупки по ее идентификатору."

DROP VIEW IF EXISTS sum_sale;

CREATE VIEW sum_sale AS SELECT magazine_sales.id_sale,

magazine_sales.id_product, magazine_sales.quantity,

prices.price, magazine_sales.quantity*prices.price AS summa

FROM magazine_sales, prices

WHERE magazine_sales.id_product=prices.id_product;

SELECT SUM(summa) FROM sum_sale WHERE id_sale=i;

Здесь перед параметром у нас появилось новое ключевое слово IN. Дело в том, что мы можем, как передавать данные в процедуру, так и передавать данные из процедуры. По умолчанию, т.е. если опустить слово IN, параметры считаются входными (поэтому раньше мы это слово и не использовали). Здесь же мы явно указали, что параметр i является входным. Если же нам понадобится извлечь какие-нибудь данные из хранимой процедуры, то мы будем использовать ключевое слово OUT, но об этом чуть позже.

Итак, мы написали процедуру, которая создает представление, выбирая идентификатор покупки, идентификатор товара, его количество, цену и подсчитывает сумму по всем строчкам получившейся таблицы. Затем идет запрос к этому представлению, где по входному параметру идентификатора покупки подсчитывается итоговая сумма этой покупки.

Теперь нам надо написать процедуру, которая пересчитает итоговую сумму с учетом предоставляемой скидки. Здесь нам и понадобится оператор ветвления:

Т.е. мы передаем процедуре два входных параметра сумму (sm) и идентификатор покупки (i) и в зависимости от того, какая это сумма, выполняется запрос к представлению sum_sale на подсчет итоговой суммы покупки, умноженной на нужный коэффициент.

Осталось только сделать так, чтобы сумма покупки автоматически передавалась в эту процедуру. Для этого процедуру sum_discount хорошо бы вызвать прямо из процедуры sum_sale. Выглядеть это будет примерно вот так:

Вопросительный знак при вызове процедуры sum_discount поставлен, т.к. не понятно, как результат предыдущего запроса (т.е. итоговой суммы) передать в процедуру sum_discount. Кроме того, не понятно, как процедура sum_discount вернет результат своей работы. Вы, наверно, уже догадались, что для решения второго вопроса нам как раз и понадобится параметр с ключевым словом OUT, т.е. параметр, который будет возвращать данные из процедуры. Давайте введем такой параметр ss, и так как сумма может быть и дробным числом, зададим ему тип DOUBLE:

Итак, в обе процедуры мы ввели выходной параметр ss. Теперь вызов процедуры CALL sum_discount(?, i, ss); означает, что передавая два первых параметра, мы ждем возврата третьего параметра в процедуру sum_sale. Осталось только понять, как внутри самой процедуры sum_discount присвоить этому параметру какое-либо значение. Нам надо, чтобы в этот параметр передавался результат одного из запросов. И, конечно, в MySQL предусмотрен такой вариант, для этого используется ключевое слово INTO:

С помощью ключевого слова INTO, мы указали, что результат запроса надо передать в параметр ss.

Теперь давайте разбираться с вопросительным знаком, вернее узнаем, как передать в процедуру sum_discount результат работы предыдущих запросов. Для этого мы познакомимся с таким понятием, как переменная.

Переменные позволяют сохранить результат текущего запроса для использования в следующих запросах. Объявление переменной начинается с символа собачки (@), за которой следует имя переменной. Объявляются они при помощи оператора SET. Например, объявим переменную z и зададим ей начальное значение 20.

Переменная с таким значение теперь есть в нашей БД, можете проверить, сделав соответствующий запрос:

Переменные действуют только в рамках одного сеанса соединения с сервером MySQL. То есть после разъединения переменная перестанет существовать.

Для использования переменных в процедурах используется оператор DECLARE, который имеет следующий синтаксис:

DECLARE имя_переменной тип DEFAULT значение_по_умолчанию_если_есть

Итак, давайте в нашей процедуре объявим переменную s, в которую будем сохранять значение суммы покупки с помощью ключевого слова INTO:

Эта переменная и будет первым входным параметром для процедуры sum_discount. Итак, окончательный вариант наших процедур выглядит так:

На случай, если вы запутались, давайте посмотрим алгоритм работы нашей процедуры sum_sale:

Мы вызываем процедуру sum_sale, указывая в качестве входного параметра идентификатор интересующей нас покупки, например id=1, и указывая, что второй параметр - выходной, переменный, являющийся результатом работы процедуры sum_discount:

call sum_sale(1, @sum_discount)//

Процедура sum_sale создает представление, в котором собираются данные обо всех покупках, товарах, их количестве, цене и сумме по каждой строчке.

Затем выполняется запрос к этому представлению на итоговую сумму по покупке с нужным идентификатором, и результат записывается в переменную s.

Теперь вызывается процедура sum_discount, в которой в качестве первого параметра выступает переменная s (сумма покупки), в качестве второго - идентификатор покупки i, а в качестве третьего указывается параметр ss, который выступает, как выходной, т.е. в него вернется результат действия процедуры sum_discount.

В процедуре sum_discount проверяется, какому условию соответствует входная сумма, и выполняется соответствующий запрос, результат записывается в выходной параметр ss, который возвращается в процедуру sum_sale.

Чтобы увидеть результат работы процедуры sum_sale нужно сделать запрос:

select @sum_discount//

Давайте убедимся, что наша процедура работает:

Сумма наших обеих покупок меньше 1000 рублей, поэтому скидки нет. Можете самостоятельно ввести покупки с разными суммами и посмотреть, как будет работать наша процедура.

Возможно, этот урок показался вам достаточно трудным или запутанным. Не расстраивайтесь. Во-первых, все приходит с опытом, а во-вторых, справедливости ради, надо сказать, что и переменные, и операторы ветвления в MySQL используются крайне редко. Предпочтение отдается языкам типа PHP, Perl и т.д., с помощью которых и организуется ветвление, а в саму БД посылаются простые процедуры.

Задание 8. Хранимые процедуры

Сегодня узнаем, как работать с циклами, т.е. выполнять один и тот же запрос несколько раз. В MySQL для работы с циклами применяются операторы WHILE, REPEAT и LOOP.

Оператор цикла WHILE

Сначала синтаксис:

WHILE условие DO

Запрос будет выполняться до тех пор, пока условие истинно. Давайте посмотрим на примере, как это работает. Предположим, мы хотим знать названия, авторов и количество книг, которые поступили в различные поставки. Интересующая нас информация хранится в двух таблицах - Журнал Поставок (magazine_incoming) и Товар (products). Давайте напишим интересующий нас запрос:

А что, если нам необходимо, чтобы результат выводился не в одной таблице, а по каждой поставке отдельно? Конечно, можно написать 3 разных запроса, добавив в каждый еще одно условие:

Но гораздо короче сделать это можно с помощью цикла WHILE:

Т.е. мы ввели переменную i, по умолчанию равную 3, сервер выполнит запрос с id поставки равным 3, затем уменьшит i на единицу (SET i=i-1), убедится, что новое значение переменной i положительно (i>0) и снова выполнит запрос, но уже с новым значением id поставки равным 2. Так будет происходить, пока переменная i не получит значение 0, условие станет ложным, и цикл закончит свою работу.

Чтобы убедиться в работоспособности цикла создадим хранимую процедуру books и поместим в нее цикл:

Теперь вызовем процедуру:

Теперь у нас 3 отдельные таблицы (по каждой поставке). Согласитесь, что код с циклом гораздо короче трех отдельных запросов. Но в нашей процедуре есть одно неудобство, мы объявили количество выводимых таблиц значением по умолчанию (DEFAULT 3), и нам придется с каждой новой поставкой менять это значение, а значит код процедуры. Гораздо удобнее сделать это число входным параметром. Давайте перепишем нашу процедуру, добавив входной параметр num, и, учитывая, что он не должен быть равен 0:

Убедитесь, что с другими параметрами, мы по-прежнему получаем таблицы по каждой поставке. У нашего цикла есть еще один недостаток - если случайно задать слишком большое входное значение, то мы получим псевдобесконечный цикл, который загрузит сервер бесполезной работой. Такие ситуации предотвращаются с помощью снабжения цикла меткой и использования оператора LEAVE, обозначающего досрочный выход из цикла.

Итак, мы снабдили наш цикл меткой wet вначале (wet:) и в конце, а также добавили еще одно условие - если входной параметр больше 10 (число 10 взято произвольно), то цикл с меткой wet следует закончить (IF (i>10) THEN LEAVE wet). Таким образом, если мы случайно вызовем процедуру с большим значением num, наш цикл прервется после 10 итераций (итерация - один проход цикла).

Циклы в MySQL, так же как и операторы ветвления, на практике в web-приложениях почти не используются. Поэтому для двух других видов циклов приведем лишь синтаксис и отличия. Вряд ли вам доведется их использовать, но знать об их существовании все-таки надо.

Оператор цикла REPEAT

Условие цикла проверяется не в начале, как в цикле WHILE, а в конце, т.е. хотя бы один раз, но цикл выполняется. Сам же цикл выполняется, пока условие ложно. Синтаксис следующий:

UNTIL условие

Оператор цикла LOOP

Этот цикл вообще не имеет условий, поэтому обязательно должен иметь оператор LEAVE. Синтаксис следующий:

На этом мы заканчиваем изучение SQL. Конечно, мы рассмотрели не все возможности этого языка запросов, но в реальной жизни вам вряд ли придется столкнуться даже с тем, что вы уже знаете.

Размещено на Allbest.ru

...

Подобные документы

    Использование встроенных функций MS Excel для решения конкретных задач. Возможности сортировки столбцов и строк, перечень функций и формул. Ограничения формул и способы преодоления затруднений. Выполнение практических заданий по использованию функций.

    лабораторная работа , добавлен 16.11.2008

    Особенности использования встроенных функций Microsoft Excel. Создание таблиц, их заполнение данными, построение графиков. Применение математических формул для выполнения запросов с помощью пакетов прикладных программ. Технические требования к компьютеру.

    курсовая работа , добавлен 25.04.2013

    Назначение и составляющие формул, правила их записи и копирования. Использование математических, статистических и логических функций, функций даты и времени в MS Excel. Виды и запись ссылок табличного процессора, технология их ввода и копирования.

    презентация , добавлен 12.12.2012

    Рассмотрение особенностей объявления функций на языке СИ. Определение понятий аргументов функции и их переменных (локальных, регистровых, внешних, статических). Решение задачи программным методом: составление блок-схемы, описание функций main и sqr.

    презентация , добавлен 26.07.2013

    Правили создания и алгоритм применения собственной функции пользователя в стандартном модуле редактора VBA. Изучение структуры кода функции. Перечень встроенных математических функций редактора Visual Basic. Определение области видимости переменной.

    практическая работа , добавлен 07.10.2010

    Создание приложения, которое будет производить построение графиков функций по заданному математическому выражению. Разработка программы "Генератор математических функций". Создание мастера функций для ввода математического выражения, тестирование.

    дипломная работа , добавлен 16.02.2016

    Проведение анализа динамики валового регионального продукта и расчета его точечного прогноза при помощи встроенных функций Excel. Применение корреляционно-регрессионного анализа с целью выяснения зависимости между основными фондами и объемом ВРП.

    реферат , добавлен 20.05.2010

    Функции, позволяющие работать с базой данных MySQL средствами РНР. Соединение с сервером и его разрыв. Создание и выбор базы данных. Доступ к отдельному полю записи. Комплексное использование информационных функций. Запросы, отправляемые серверу MySQL.

    лекция , добавлен 27.04.2009

    Разработка приложения, которое будет выполнять функции показа точного времени и точной даты. Определение дополнительных функций разработанного приложения. Рассмотрение основных этапов создания программного продукта. Результаты тестирования приложения.

    курсовая работа , добавлен 14.04.2019

    Программное вычисление по формулам, определение площади правильного многоугольника для любых возможных исходных данных, использование потоков ввода-вывода. Использование операторов при вычислении математических функций, алгоритмы накопления суммы.

Внимание! Данная работа построена на основе перевода раздела «17.1. Stored Routines and the Grant Tables» описания ПО MySQL 5.0.19, «Reference Manual. It documents MySQL 5.0 through 5.0.19. Document generated on: 2006-01-23 (revision:995)»
``Сначала прочти все, а потом пробуй примеры"

Хранимые процедуры представляют собой набор команд SQL, которые могут компилироваться и храниться на сервере. Таким образом, вместо того, чтобы хранить часто используемый запрос, клиенты могут ссылаться на соответствующую хранимую процедуру. Это обеспечивает лучшую производительность, поскольку данный запрос должен анализироваться только однажды и уменьшается трафик между сервером и клиентом. Концептуальный уровень можно также повысить за счет создания на сервере библиотеки функций.

Триггер представляет собой хранимую процедуру, которая активизируется при наступлении определенного события. Например, можно задать хранимую процедуру, которая срабатывает каждый раз при удалении записи из транзакционной таблицы - таким образом, обеспечивается автоматическое удаление соответствующего заказчика из таблицы заказчиков, когда все его транзакции удаляются.

Хранимые программы (процедуры и функции) поддерживаются в MySQL 5.0. Хранимые процедуры - набор SQL -выражений, который может быть сохранен на сервере. Как только это сделано, клиенту уже не нужно повторно передавать запрос, а требуется просто вызвать хранимую программу.

Это может быть полезным тогда, когда:

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

Хранимые процедуры и функции (подпрограммы) могут обеспечить лучшую производительность потому, что меньше информации требуется для пересылки между клиентом и сервером. Выбор увеличивает нагрузку на сервер БД, но снижает затраты на стороне клиента. Используйте это, если много клиентских машин (таких как Веб-серверы) обслуживаются одной или несколькими БД.

Хранимые подпрограммы также позволяют вам использовать библиотеки функций, хранимые в БД сервера. Эта возможность представлена для многих современных языков программирования, которые позволяют вызывать их непосредственно (например, используя классы).

MySQL следует в синтаксисе за SQL:2003 для хранимых процедур, который уже используется в IBM"s DB2.

От слов к делу…

При создании, модификации, удалении хранимых подпрограмм сервер манипулирует с таблицей mysql.proc

Начиная с MySQL 5.0.3 требуются следующие привилегии:

CREATE ROUTINE для создания хранимых процедур

ALTER ROUTINE необходимы для изменения или удаления процедур. Эта привилегия автоматически назначается создателю процедуры (функции)

EXECUTE привилегия потребуется для выполнения подпрограммы. Тем не менее, автоматически назначается создателю процедуры (функции). Также, по умолчанию, SQL SECURITY параметр для подпрограммы DEFINER , который разрешает пользователям, имеющим доступ к БД вызывать подпрограммы, ассоциированные с этой БД.

Синтаксис хранимых процедур и функций

Хранимая подпрограмма представляет собой процедуру или функцию. Хранимые подпрограммы создаются с помощью выражений CREATE PROCEDURE или CREATE FUNCTION . Хранимая подпрограмма вызывается, используя выражение CALL , причем только возвращающие значение переменные используются в качестве выходных. Функция может быть вызвана подобно любой другой функции и может возвращать скалярную величину. Хранимые подпрограммы могут вызывать другие хранимые подпрограммы.

Начиная с MySQL 5.0.1, загруженная процедура или функция связана с конкретной базой данных. Это имеет несколько смыслов:

  • Когда подпрограмма вызывается, то подразумевается, что надо произвести вызов USE db_name (и отменить использование базы, когда подпрограмма завершилась, и база больше не потребуется)
  • Вы можете квалифицировать обычные имена с именем базы данных. Это может быть использовано, чтобы ссылаться на подпрограмму, которая - не в текущей базе данных. Например, для выполнения хранимой процедуры p или функции f которые связаны с БД test , вы можете сказать интерпретатору команд так: CALL test.p() или test.f() .
  • Когда база данных удалена, все загруженные подпрограммы связанные с ней тоже удаляются. В MySQL 5.0.0, загруженные подпрограммы - глобальные и не связанны с базой данных. Они наследуют по умолчанию базу данных из вызывающего оператора. Если USE db_name выполнено в пределах подпрограммы, оригинальная текущая БД будет восстановлена после выхода из подпрограммы (Например текущая БД db_11 , делаем вызов подпрограммы, использующей db_22 , после выхода из подпрограммы остается текущей db_11)

MySQL поддерживает полностью расширения, которые разрешают юзать обычные SELECT выражения (без использования курсоров или локальных переменных) внутри хранимых процедур. Результирующий набор, возвращенный от запроса, а просто отправляется напрямую клиенту. Множественный SELECT запрос генерирует множество результирующих наборов, поэтому клиент должен использовать библиотеку, поддерживающую множественные результирующие наборы.

CREATE PROCEDURE - создать хранимую процедуру.

CREATE FUNCTION - создать хранимую функцию.

Синтаксис:

CREATE PROCEDURE имя_процедуры ([параметр_процедуры[,...]])
[характеристёика...] тело_подпрограммы

CREATE FUNCTION имя_функции ([параметр_функции[,...]])
RETURNS тип
[характеристика...] тело_подпрограммы

параметр_процедуры:
[ IN | OUT | INOUT ] имя_параметра тип
параметр_функции:
имя_параметра тип

тип:
Любой тип данных MySQL

характеристика:
LANGUAGE SQL
| DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT "string"

тело_подпрограммы:
Правильное SQL выражение.

Рассмотрим все на практике.

Сначала создадим хранимую процедуру следующим запросом:

CREATE PROCEDURE `my_proc`(OUT t INTEGER(11))
NOT DETERMINISTIC
SQL SECURITY INVOKER
COMMENT ""
BEGIN
select val1+val2 into "t" from `my` LIMIT 0,1;
END;

Применение выражения LIMIT в этом запросе сделано из соображений того, что не любой клиент способен принять многострочный результирующий набор.

После этого вызовем ее:

CALL my_proc(@a);
SELECT @a;

Для отделения внутреннего запроса от внешнего всегда используют разделитель отличный от обычно (для задания используют команду DELIMITER <строка/символ>)

Вот еще один пример с учетом всех требований.

Mysql> delimiter //
mysql> CREATE PROCEDURE simpleproc (OUT param1 INT)
-> BEGIN
-> SELECT COUNT(*) INTO param1 FROM t;
-> END;
-> //

mysql> delimiter ;
mysql> CALL simpleproc(@a);
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @a;
+------+
| @a |
+------+
| 3 |
+------+
1 row in set (0.00 sec)

Весь процесс можно пронаблюдать на рисунке ниже:

Триггеры

Поддержка триггеров появилась в MySQL начиная с версии 5.0.2.

Триггер - поименованный объект БД, который ассоциирован с таблицей и активируемый при наступлении определенного события, события связанного с этой таблицей.

Например, нижеприведенный код создает таблицу и INSERT триггер. Триггер суммирует значения, вставляемые в один из столбцов таблицы.

Mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
Query OK, 0 rows affected (0.03 sec)
mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
-> FOR EACH ROW SET @sum = @sum + NEW.amount;
Query OK, 0 rows affected (0.06 sec)

Объявим переменную sum и присвоим ей значение 1. После этого при каждой вставке в таблицу account значение этой переменной будет увеличивать согласно вставляемой части.

Замечание . Если значение переменной не инициализировано, то триггер работать не будет!

Синтаксис создания триггера

CREATE

TRIGGER имя_триггера время_триггера событие_срабатывания_триггера
ON имя_таблицы FOR EACH ROW выражение_выполняемое_при_срабатывании_триггера

Если с именем триггера и именем пользователя все понятно сразу, то о «времени триггера» и «событии» поговорим отдельно.

время_триггера

Определяет время свершения действия триггера. BEFORE означает, что триггер выполнится до завершения события срабатывания триггера, а AFTER означает, что после. Например, при вставке записей (см. пример выше) наш триггер срабатывал до фактической вставки записи и вычислял сумму. Такой вариант уместен при предварительном вычислении каких-то дополнительных полей в таблице или параллельной вставке в другую таблицу.

событие_срабатывания_триггера

Здесь все проще. Тут четко обозначается, при каком событии выполняется триггер.

  • INSERT: т.е. при операциях вставки или аналогичных ей выражениях (INSERT, LOAD DATA, и REPLACE)
  • UPDATE: когда сущность (строка) модифицирована
  • DELETE: когда запись удаляется (запросы, содержащие выражения DELETE и/или REPLACE)

В этой части статьи допишем начатую в предыдущей статье хранимую процедуру и научимся создавать хранимые mysql функции .

И так нам осталось указать значение для последней переменной PostID. В качестве значения ей будет присвоен результат, который вернёт функция GetPostID, которую сейчас и создадим.

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

Для начала закрываем текущую форму создания процедуры, нажав на кнопку c надписью Go. Затем в этом же окне снова нажимаем на надпись Add routine, появится знакомая форма, заполним её.

Имя - GetPostID Тип - функция Parameters - ComID BIGINT(20) UNSIGNED Return type (возвращаемый тип) - BIGINT Return length/values - 20 Return options - UNSIGNED Definition: BEGIN RETURN (SELECT comment_post_ID FROM wp_comments WHERE comment_ID = ComID); END;

Так же можно указать дополнительные параметры:

Is deterministic — детерминированная функция всегда возвращает один и тот же результат при одинаковых входных параметрах иначе она является не детерминированной. В нашем случае ставим галочку.

Definer и Security type параметры безопасности, в данном примере оставим их без изменений.

SQL data access имеет несколько значений:

NO SQL - не содержит sql.

Contains SQL - содержит встроенные sql функции или операторы, которые не читают, не пишут и не изменяют данные в базе данных. Например, установка значения переменной: SET name = значение;

READS SQL DATA - только чтение данных, без любой модификации данных, указывается для запроса SELECT.

MODIFIES SQL DATA - изменение или внесение данных, в базу данных, указывается для запросов: INSERT, UPDATE, но при этом не должен присутствовать запрос SELECT.

В нашей функции используется запрос SELECT, укажем READS SQL DATA.

Comment комментарий.

После того как все поля заполнены, нажимаем на кнопку с надписью Go.

Возвращаемся на вкладку Routines и отредактируем нашу процедуру, нажав на кнопку edit.

Присвоим переменой PostID в качестве значения результат, который вернёт функция GetPostID.

SET postID = GetPostID(ComID);

В результате окончательное тело процедуры будет таким

BEGIN DECLARE Author tinytext DEFAULT "admin"; DECLARE UserID bigint(20) DEFAULT 1; DECLARE Email varchar(100); DECLARE Date DATETIME DEFAULT NOW(); DECLARE ParentCom varchar(20); DECLARE Approved varchar(20); DECLARE PostID BIGINT(20); IF Author = "admin" THEN SET Approved = 1; ELSE SET Approved = 0; END IF; SET ParentCom = ComID ; SET Email = "[email protected]"; SET PostID = GetPostID(ComID); INSERT INTO wp_comments (comment_author, comment_author_email, comment_content, comment_date, comment_date_gmt, comment_post_id, comment_parent, comment_approved, user_id) VALUES (Author, Email, Content, Date, Date, PostID, ParentCom, Approved, UserID); END;

Остальные поля формы оставим без изменений, нажимаем на кнопку Go. Процедура создана.

Так же можно установить значения для одной или нескольких переменных в результате выполнения запроса. Например, поля: Автор, почта и id пользователя хранятся в таблице wp_users.

Зная это можно установить значения для этих переменных следующим образом:

BEGIN -- Объявляем переменные DECLARE Author tinytext DEFAULT "admin"; DECLARE UserID bigint(20) DEFAULT 1; DECLARE Email varchar(100); -- выполнение запроса и установка значений для переменных SELECT user_login, user_email, ID INTO Author, Email, UserID FROM wp_users WHERE user_login LIKE "adm%"; END;

Вызов хранимой процедуры

Осталось протестировать созданную процедуру. Для начала добавим комментарий к любой статье, одобрим его и проверим, чтобы он отображался на странице.

Затем узнаем id добавленного комментария

Возвращаемся на вкладку Routines и нажимаем на надпись Execute

Появится форма

Указываем значения передаваемых параметров: текст ответа и id комментария, после чего нажимаем на кнопку с надписью Go.

математический функция программирование

Функции - это операции, позволяющие манипулировать данными. В MySQL можно выделить несколько групп встроенных функций:

Строковые функции . Используются для управления текстовыми строками, например, для обрезания или заполнения значений.

Числовые функции . Используются для выполнения математических операций над числовыми данными. К числовым функциям относятся функции возвращающие абсолютные значения, синусы и косинусы углов, квадратный корень числа и т.д. Используются они только для алгебраических, тригонометрических и геометрических вычислений. В общем, используются редко, поэтому рассматривать их мы не будем. Но вы должны знать, что они существуют, и в случае необходимости обратиться к документации MySQL.

Итоговые функции . Используются для получения итоговых данных по таблицам, например, когда надо просуммировать какие-либо данные без их выборки.

Функции даты и времени . Используются для управления значениями даты и времени, например, для возвращения разницы между датами.

Системные функции . Возвращают служебную информацию СУБД.

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

Давайте в качестве примера рассмотрим интернет-магазин.

Концептуальная модель:

Реляционная модель:


Итак, смотрим на последнюю схему и создаем БД - shop.

create database shop;

Выбираем ее для работы:

И создаем в ней 8 таблиц, как в схеме: Покупатели (customers), Поставщики (vendors), Покупки (sale), Поставки (incoming), Журнал покупок (magazine_sales), Журнал поставок (magazine_incoming), Товары (products), Цены (prices). Один нюанс, наш магазин будет торговать книгами, поэтому в таблицу Товары мы добавим еще один столбец - Автор (author), в принципе это необязательно, но так как-то привычнее.

Обратите внимание, что в таблицах Журнал покупок, Журнал поставок и Цены первичные ключи - составные, т.е. их уникальные значения состоят из пар значений (в таблице не может быть двух строк с одинаковыми парами значений). Названия столбцов этих пар значений и указываются через запятую после ключевого слова PRIMARY KEY.

В настоящем интернет-магазине данные в эти таблицы будут заноситься посредством сценариев на каком-либо языке (типа php), нам же пока придется внести их вручную. Можете внести любые данные, только помните, что значения в одноименных столбцах связанных таблиц должны совпадать. Либо скопируйте нижеприведенные данные.

3.1 дПВБЧМЕОЙЕ ОПЧЩИ ЖХОЛГЙК Ч MySQL

еУФШ ДЧБ УРПУПВБ ДПВБЧЙФШ ОПЧХА ЖХОЛГЙА Ч MySQL:

  • чЩ НПЦЕФЕ ДПВБЧЙФШ ЖХОЛГЙА ЮЕТЕЪ НЕИБОЙЪН ПРТЕДЕМСЕНЩИ РПМШЪПЧБФЕМЕН ЖХОЛГЙК (user-definable function, UDF). пОЙ ДПВБЧМСАФУС ДЙОБНЙЮЕУЛЙ, ЙУРПМШЪХС ЛПНБОДЩ CREATE FUNCTION Й DROP FUNCTION . рПДТПВОПУФЙ Ч ТБЪДЕМЕ " ".
  • чЩ НПЦЕФЕ ДПВБЧЙФШ ЖХОЛГЙА ЛБЛ ЧОХФТЕООАА Ч MySQL. фБЛЙЕ ЖХОЛГЙЙ ЛПНРЙМЙТХАФУС РТСНП ЧОХФТШ УЕТЧЕТБ mysqld Й УФБОПЧСФУС ДПУФХРОЩНЙ ОБ РПУФПСООПК ПУОПЧЕ.

лБЦДЩК НЕФПД ЙНЕЕФ УЧПЙ РТПВМЕНЩ:

  • еУМЙ чЩ РЙЫЕФЕ ПРТЕДЕМСЕНХА РПМШЪПЧБФЕМЕН ЖХОЛГЙА, чЩ ДПМЦОЩ ХУФБОПЧЙФШ ПВЯЕЛФОЩК ЖБКМ Ч ДПРПМОЕОЙЕ Л УЕТЧЕТХ. еУМЙ чЩ ЛПНРЙМЙТХЕФЕ чБЫХ ЖХОЛГЙА РТСНП Ч УЕТЧЕТ, чЩ ОЕ ДПМЦОЩ ДЕМБФШ ЬФПЗП.
  • чЩ НПЦЕФЕ ДПВБЧМСФШ UDF Л ДЧПЙЮОПНХ ДЙУФТЙВХФЙЧХ MySQL. чУФТПЕООЩЕ ЖХОЛГЙЙ ФТЕВХАФ, ЮФПВЩ чЩ ЙЪНЕОЙМЙ ЙУИПДОЙЛЙ.
  • еУМЙ чЩ ПВОПЧМСЕФЕ MySQL, чЩ НПЦЕФЕ РТПДПМЦБФШ ЙУРПМШЪПЧБФШ чБЫ РТЕДЧБТЙФЕМШОП ХУФБОПЧМЕООЩК UDF. дМС ЧУФТПЕООЩИ ЖХОЛГЙК чЩ ДПМЦОЩ РПЧФПТЙФШ НПДЙЖЙЛБГЙЙ ЛБЦДЩК ТБЪ, ЛПЗДБ чЩ ДЕМБЕФЕ БРЗТЕКД.

оЕЪБЧЙУЙНП ПФ НЕФПДБ, ЛПФПТЩК чЩ ЙУРПМШЪХЕФЕ, ЮФПВЩ ДПВБЧЙФШ ОПЧЩЕ ЖХОЛГЙЙ, ПОЙ НПЗХФ ЙУРПМШЪПЧБФШУС ФПЮОП ФБЛ ЦЕ ЛБЛ НЕУФОЩЕ ЖХОЛГЙЙ ФЙРБ ABS() ЙМЙ SOUNDEX() .

3.1.1 уЙОФБЛУЙУ CREATE FUNCTION/DROP FUNCTION

CREATE FUNCTION function_name RETURNS {STRING|REAL|INTEGER} SONAME shared_library_name DROP FUNCTION function_name

пРТЕДЕМСЕНЩЕ РПМШЪПЧБФЕМЕН ЖХОЛГЙЙ (user-definable function, UDF) РТЕДУФБЧМСАФ УПВПК УРПУПВ ТБУЫЙТЙФШ MySQL ОПЧПК ЖХОЛГЙЕК, ЛПФПТБС ТБВПФБЕФ РПДПВОП НЕУФОЩН (ЧУФТПЕООЩН) ЖХОЛГЙСН MySQL ФЙРБ ABS() ЙМЙ CONCAT() .

AGGREGATE ОПЧБС ПРГЙС ДМС MySQL Version 3.23. жХОЛГЙС У AGGREGATE ТБВПФБЕФ ФПЮОП ФБЛ ЦЕ, ЛБЛ Й ЧУФТПЕООБС ЖХОЛГЙС GROUP , РПДПВОП SUM ЙМЙ COUNT() .

CREATE FUNCTION УПИТБОСЕФ ЙНС ЖХОЛГЙЙ, ФЙР Й ПВЭЕДПУФХРОПЕ ВЙВМЙПФЕЮОПЕ ЙНС Ч ФБВМЙГЕ mysql.func УЙУФЕНЩ. чЩ ДПМЦОЩ ЙНЕФШ РТЙЧЙМЕЗЙЙ insert Й delete ДМС ВБЪЩ ДБООЩИ mysql , ЮФПВЩ УПЪДБЧБФШ Й ХДБМСФШ ЖХОЛГЙЙ.

чУЕ БЛФЙЧОЩЕ ЖХОЛГЙЙ РЕТЕЪБЗТХЦБАФУС РТЙ ЛБЦДПН ЪБРХУЛЕ УЕТЧЕТБ, ЕУМЙ чЩ ОЕ ЪБРХУЛБЕФЕ mysqld У ПРГЙЕК --skip-grant-tables . ч ЬФПН УМХЮБЕ ЙОЙГЙБМЙЪБГЙС РТПРХЭЕОБ, Й UDF УФБОХФ ОЕДПУФХРОЩ. бЛФЙЧОБС ЖХОЛГЙС РТЕДУФБЧМСЕФ УПВПК ФБЛХА ЖХОЛГЙА, ЛПФПТБС ВЩМБ ЪБЗТХЦЕОБ У РПНПЭША CREATE FUNCTION , ОП ОЕ ВЩМБ ХДБМЕОБ ЮЕТЕЪ ЧЩЪПЧ DROP FUNCTION .

рП РПЧПДХ РТБЧЙМ ОБРЙУБОЙС ПРТЕДЕМСЕНЩИ РПМШЪПЧБФЕМЕН ЖХОЛГЙК ПФУЩМБА чБУ Л ТБЪДЕМХ "3.1 дПВБЧМЕОЙЕ ОПЧПК ЖХОЛГЙЙ, ПРТЕДЕМСЕНПК РПМШЪПЧБФЕМЕН Ч MySQL ". дМС ТБВПФЩ НЕИБОЙЪНБ UDF ЖХОЛГЙЙ ДПМЦОЩ ВЩФШ ОБРЙУБОЩ ОБ C ЙМЙ C++, чБЫБ ПРЕТБГЙПООБС УЙУФЕНБ ДПМЦОБ РПДДЕТЦЙЧБФШ ДЙОБНЙЮЕУЛХА ЪБЗТХЪЛХ, Й mysqld ДПМЦЕО ВЩФШ ПФЛПНРЙМЙТПЧБО ДЙОБНЙЮЕУЛЙ (ОЕ УФБФЙЮЕУЛЙ).

3.1.2 дПВБЧМЕОЙЕ ОПЧПК ЖХОЛГЙЙ, ПРТЕДЕМСЕНПК РПМШЪПЧБФЕМЕН

дМС ТБВПФЩ НЕИБОЙЪНБ UDF ЖХОЛГЙЙ ДПМЦОЩ ВЩФШ ОБРЙУБОЩ ОБ C ЙМЙ C++, Б чБЫБ ПРЕТБГЙПООБС УЙУФЕНБ ДПМЦОБ РПДДЕТЦЙЧБФШ ДЙОБНЙЮЕУЛХА ЪБЗТХЪЛХ. дЙУФТЙВХФЙЧ ЙУИПДОЙЛПЧ MySQL ЧЛМАЮБЕФ ЖБКМ sql/udf_example.cc , ЛПФПТЩК ПРТЕДЕМСЕФ 5 ОПЧЩИ ЖХОЛГЙК. лПОУХМШФЙТХКФЕУШ У ЬФЙН ЖБКМПН, ЮФПВЩ ЧЙДЕФШ, ЛБЛ ТБВПФБАФ УПЗМБЫЕОЙС П ЧЩЪПЧБИ 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"" ЙУРПМШЪХЕФУС ДМС ЙНЕОЙ ЖХОЛГЙЙ РТЙНЕТБ. ъДЕУШ XXX() (ЧЕТИОЙК ТЕЗЙУФТ) ХЛБЪЩЧБЕФ SQL-ПВТБЭЕОЙЕ Л ЖХОЛГЙЙ, Й xxx() (ОЙЦОЙК ТЕЗЙУФТ) ХЛБЪЩЧБЕФ C/C++-ПВТБЭЕОЙЕ Л ЖХОЛГЙЙ.

жХОЛГЙЙ, ЛПФПТЩЕ чЩ РЙЫЕФЕ ОБ C/C++ ДМС ТЕБМЙЪБГЙЙ ЙОФЕТЖЕКУБ У XXX() :

Xxx() (ПВСЪБФЕМШОБ) пУОПЧОБС ЖХОЛГЙС. ьФП ФП НЕУФП, ЗДЕ ЖХОЛГЙПОБМШОЩК ТЕЪХМШФБФ ЧЩЮЙУМЕО. уППФЧЕФУФЧЙЕ НЕЦДХ ФЙРПН SQL Й ФЙРПН ЧПЪЧТБФБ чБЫЕК ЖХОЛГЙЙ ОБ C/C++ РПЛБЪЩЧБЕФУС ОЙЦЕ:

SQL-ФЙР C/C++-ФЙР
STRING char *
INTEGER long long
REAL double
xxx_init() (ПРГЙПОБМШОБ) жХОЛГЙС ЙОЙГЙБМЙЪБГЙЙ ДМС xxx() . ьФП НПЦЕФ ЙУРПМШЪПЧБФШУС ДМС:
  • рТПЧЕТЛЙ ЮЙУМБ РБТБНЕФТПЧ XXX() .
  • рТПЧЕТЛЙ, ЮФП РБТБНЕФТЩ ЙНЕАФ ФТЕВХЕНЩК ФЙР ЙМЙ ЧЩДБЮЙ РТЕДРЙУБОЙС, ЮФПВЩ MySQL РТЙОХДЙФЕМШОП РТЙЧЕМ РБТБНЕФТЩ Л ФЙРБН, ЛПФПТЩЕ чЩ ИПФЙФЕ ЙНЕФШ, ЛПЗДБ ПУОПЧОБС ЖХОЛГЙС ЧЩЪЧБОБ.
  • тБУРТЕДЕМЕОЙС МАВПК РБНСФШ, ФТЕВХЕНПК ДМС ПУОПЧОПК ЖХОЛГЙЙ.
  • пРТЕДЕМЕОЙС НБЛУЙНБМШОПК ДМЙОЩ ТЕЪХМШФБФБ.
  • хЛБЪБОЙС (ДМС ЖХОЛГЙК ФЙРБ REAL) НБЛУЙНБМШОПЗП ЛПМЙЮЕУФЧБ ДЕУСФЙЮОЩИ ЮЙУЕМ.
  • хЛБЪБОЙС ФПЗП, НПЦЕФ ЙМЙ ОЕФ ТЕЪХМШФБФ ВЩФШ NULL .
xxx_deinit() (ПРГЙПОБМШОП) жХОЛГЙС ДЕЙОЙГЙБМЙЪБГЙЙ ДМС xxx() . ьФП ДПМЦОП ПУЧПВПДЙФШ МАВХА РБНСФШ, ТБУРТЕДЕМЕООХА ЖХОЛГЙЕК ЙОЙГЙБМЙЪБГЙЙ.

лПЗДБ ЙОУФТХЛГЙС SQL ЧЩЪЩЧБЕФ XXX() , MySQL ЧЩЪЩЧБЕФ ЖХОЛГЙА ЙОЙГЙБМЙЪБГЙЙ xxx_init() , ЮФПВЩ РПЪЧПМЙФШ ЕК ЧЩРПМОЙФШ МАВХА ФТЕВХЕНХА ОБУФТПКЛХ, ФЙРБ РТПЧЕТЛЙ РБТБНЕФТБ ЙМЙ ТБУРТЕДЕМЕОЙС РБНСФЙ. еУМЙ xxx_init() ЧПЪЧТБЭБЕФ ПЫЙВЛХ, ЙОУФТХЛГЙС SQL ВХДЕФ РТЕТЧБОБ У УППВЭЕОЙЕН ПВ ПЫЙВЛЕ, РТЙЮЕН ЗМБЧОБС Й ДЕЙОЙГЙБМЙЪБГЙПООБС ЖХОЛГЙЙ ОЕ ВХДХФ ЧЩЪЧБОЩ, ЮФП УФПЙФ ЙНЕФШ Ч ЧЙДХ РТЙ ТБУРТЕДЕМЕОЙЙ РБНСФЙ. йОБЮЕ ПУОПЧОБС ЖХОЛГЙС xxx() ВХДЕФ ЧЩЪЧБОБ ПДЙО ТБЪ ДМС ЛБЦДПК УФТПЛЙ. рПУМЕ ФПЗП, ЛБЛ ЧУЕ УФТПЛЙ ВЩМЙ ПВТБВПФБОЩ, ЧЩЪЩЧБЕФУС ЖХОЛГЙС xxx_deinit() , ФБЛ ЮФП ПОБ НПЦЕФ ЧЩРПМОЙФШ ФТЕВХЕНХА ПЮЙУФЛХ.

чУЕ ЖХОЛГЙЙ ДПМЦОЩ ВЩФШ ВЕЪПРБУОЩ ДМС РПФПЛПЧ (ОЕ ФПМШЛП ПУОПЧОБС ЖХОЛГЙС, ОП Й ПУФБМШОЩЕ: ЙОЙГЙБМЙЪБГЙС Й ДЕЙОЙГЙБМЙЪБГЙС ЙДХФ Ч РПФПЮОПН ТЕЦЙНЕ!). ьФП ПЪОБЮБЕФ, ЮФП чБН ОЕ РПЪЧПМСФ ТБУРТЕДЕМЙФШ МАВЩЕ ЗМПВБМШОЩЕ ЙМЙ НЕОСФШ УФБФЙЮЕУЛЙЕ РЕТЕНЕООЩЕ! еУМЙ чЩ ОХЦДБЕФЕУШ Ч РБНСФЙ, чЩ ДПМЦОЩ ТБУРТЕДЕМЙФШ ЕЕ Ч xxx_init() Й ОЕРТЕНЕООП ПУЧПВПДЙФШ Ч xxx_deinit() .

3.1.2.1 уПЗМБЫЕОЙС РП ЧЩЪПЧХ UDF

пУОПЧОБС ЖХОЛГЙС ДПМЦОБ ВЩФШ ПВЯСЧМЕОБ ЛБЛ РПЛБЪБОП ОЙЦЕ. пВТБФЙФЕ ЧОЙНБОЙЕ, ЮФП ФЙР ЧПЪЧТБФБ Й РБТБНЕФТЩ ПФМЙЮБАФУС Ч ЪБЧЙУЙНПУФЙ ПФ ФПЗП, ПВЯСЧЙФЕ МЙ чЩ ФЙР ЧПЪЧТБФБ ЖХОЛГЙЙ SQL XXX() ЛБЛ STRING , INTEGER ЙМЙ REAL Ч ЧЩЪПЧЕ CREATE FUNCTION:

дМС ЖХОЛГЙК ФЙРБ STRING:

Char *xxx(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);

дМС ЖХОЛГЙК ФЙРБ INTEGER:

Long long xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error);

дМС ЖХОЛГЙК ФЙРБ REAL:

Double xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error);

жХОЛГЙЙ ЙОЙГЙБМЙЪБГЙЙ Й ДЕЙОЙГЙБМЙЪБГЙЙ ПВЯСЧМЕОЩ РПДПВОП ЬФПНХ:

My_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message); void xxx_deinit(UDF_INIT *initid);

рБТБНЕФТ initid РЕТЕДБО ЧУЕН ФТЕН ЖХОЛГЙСН. пО ХЛБЪЩЧБЕФ ОБ УФТХЛФХТХ UDF_INIT , ЛПФПТБС ЙУРПМШЪХЕФУС, ЮФПВЩ РЕТЕДБФШ ЙОЖПТНБГЙА НЕЦДХ ЖХОЛГЙСНЙ. юМЕОЩ УФТХЛФХТЩ UDF_INIT РЕТЕЮЙУМЕОЩ ОЙЦЕ. жХОЛГЙС ЙОЙГЙБМЙЪБГЙЙ ДПМЦОБ ЪБРПМОЙФШ МАВЩЕ ЮМЕОЩ, ЛПФПТЩЕ ПОБ ЦЕМБЕФ ЙЪНЕОЙФШ. юФПВЩ ЙУРПМШЪПЧБФШ ЪОБЮЕОЙЕ РП ХНПМЮБОЙА ДМС ЮМЕОБ, ПУФБЧШФЕ ЕЗП ОЕЙЪНЕООЩН. рЕТЕКДЕН Л ПРЙУБОЙА:

My_bool maybe_null xxx_init() ДПМЦОБ ХУФБОПЧЙФШ maybe_null Ч 1 , ЕУМЙ xxx() НПЦЕФ ЧПЪЧТБЭБФШ NULL . ъОБЮЕОЙЕ РП ХНПМЮБОЙА 1 , ЕУМЙ МАВПК ЙЪ РБТБНЕФТПЧ ПВЯСЧМЕО ЛБЛ maybe_null . unsigned int decimals юЙУМП ДЕУСФЙЮОЩИ ГЙЖТ. ъОБЮЕОЙЕ РП ХНПМЮБОЙА: НБЛУЙНБМШОПЕ ЛПМЙЮЕУФЧП ДЕУСФЙЮОЩИ ГЙЖТ Ч РБТБНЕФТБИ, РЕТЕДБООЩИ ПУОПЧОПК ЖХОЛГЙЙ. оБРТЙНЕТ, ЕУМЙ ЖХОЛГЙЙ РЕТЕДБОЩ 1.34 , 1.345 Й 1.3 , ЪОБЮЕОЙЕН РП ХНПМЮБОЙА ВХДЕФ 3, РПУЛПМШЛХ 1.345 ЙНЕЕФ 3 ДЕУСФЙЮОЩИ ГЙЖТЩ. unsigned int max_length нБЛУЙНБМШОБС ДМЙОБ ТЕЪХМШФБФБ-УФТПЛЙ. ъОБЮЕОЙЕ РП ХНПМЮБОЙА ПФМЙЮБЕФУС Ч ЪБЧЙУЙНПУФЙ ПФ ФЙРБ ТЕЪХМШФБФБ ЖХОЛГЙЙ. дМС УФТПЮОЩИ ЖХОЛГЙК ЪОБЮЕОЙЕ РП ХНПМЮБОЙА ТБЧОП ДМЙОЕ УБНПЗП ДМЙООПЗП РБТБНЕФТБ. дМС ГЕМПЮЙУМЕООЩИ ЖХОЛГЙК ЪОБЮЕОЙЕ РП ХНПМЮБОЙА УППФЧЕФУФЧХЕФ 21 ГЙЖТЕ. дМС ТЕБМШОЩИ ЖХОЛГЙК ЪОБЮЕОЙЕ РП ХНПМЮБОЙА 13+ЛПМЙЮЕУФЧП ДЕУСФЙЮОЩИ ЮЙУЕМ, ПВПЪОБЮЕООЩИ ЛБЛ initid->decimals . дМС ЮЙУМПЧЩИ ЖХОЛГЙК ДМЙОБ ЧЛМАЮБЕФ МАВПК ЪОБЛ ЙМЙ ДЕУСФЙЮОЩЕ УЙНЧПМЩ ПФНЕФЛЙ. char *ptr хЛБЪБФЕМШ, ЛПФПТЩК ЖХОЛГЙС НПЦЕФ ЙУРПМШЪПЧБФШ ДМС УПВУФЧЕООЩИ ГЕМЕК. оБРТЙНЕТ, ЖХОЛГЙЙ НПЗХФ ЙУРПМШЪПЧБФШ initid->ptr , ЮФПВЩ РЕТЕДБФШ ТБУРТЕДЕМЕООХА РБНСФШ НЕЦДХ ЖХОЛГЙСНЙ. ч xxx_init() ЛБЛ ПВЩЮОП ТБУРТЕДЕМЙФЕ РБНСФШ Й ОБЪОБЮШФЕ ЕЕ ЬФПНХ ХЛБЪБФЕМА: initid->ptr=allocated_memory; ч xxx() Й xxx_deinit() ПВТБФЙФЕУШ Л initid->ptr , ЮФПВЩ ЙУРПМШЪПЧБФШ ЙМЙ ПУЧПВПДЙФШ РБНСФШ.

3.1.2.2 пВТБВПФЛБ РБТБНЕФТПЧ

рБТБНЕФТ args ХЛБЪЩЧБЕФ ОБ УФТХЛФХТХ UDF_ARGS , ЮМЕОЩ ЛПФПТПК РТЙЧЕДЕОЩ ОЙЦЕ:

Unsigned int arg_count юЙУМП РБТБНЕФТПЧ. рТПЧЕТШФЕ ЬФП ЪОБЮЕОЙЕ Ч ЖХОЛГЙЙ ЙОЙГЙБМЙЪБГЙЙ, ЕУМЙ чЩ ИПФЙФЕ, ЮФПВЩ чБЫБ ЖХОЛГЙС ВЩМБ ЧЩЪЧБОБ УП УРЕГЙЖЙЮЕУЛЙН ЮЙУМПН РБТБНЕФТПЧ. оБРТЙНЕТ, ФБЛЙН ЛПДПН: if (args->arg_count != 2) { strcpy(message,"XXX() requires two arguments"); return 1; } enum Item_result *arg_type фЙРЩ ДМС ЛБЦДПЗП РБТБНЕФТБ. чПЪНПЦОЩЕ ЪОБЮЕОЙС ФЙРПЧ: STRING_RESULT , INT_RESULT Й REAL_RESULT . юФПВЩ ХДПУФПЧЕТЙФШУС, ЮФП РБТБНЕФТЩ ЙНЕАФ ДБООЩК ФЙР Й ЧПЪЧТБЭБАФ ПЫЙВЛХ, ЕУМЙ ПОЙ Л ОЕНХ ОЕ РТЙОБДМЕЦБФ, РТПЧЕТШФЕ НБУУЙЧ arg_type Ч ЖХОЛГЙЙ ЙОЙГЙБМЙЪБГЙЙ. оБРТЙНЕТ: if (args->arg_type != STRING_RESULT || args->arg_type != INT_RESULT) { strcpy(message,"XXX() requires a string and an integer"); return 1; } чЩ НПЦЕФЕ ЙУРПМШЪПЧБФШ ЖХОЛГЙА ЙОЙГЙБМЙЪБГЙЙ, ЮФПВЩ ХУФБОПЧЙФШ ЬМЕНЕОФЩ arg_type Л ФЙРБН, ЛПФПТЩЕ чЩ ИПФЙФЕ РПМХЮЙФШ. ьФП ЪБУФБЧМСЕФ MySQL РТЙЧЕУФЙ РБТБНЕФТЩ Л ФЕН ФЙРБН ДМС ЛБЦДПЗП ПВТБЭЕОЙС Л xxx() . оБРТЙНЕТ, ЮФПВЩ ПРТЕДЕМЙФШ РЕТЧЩЕ ДЧБ ЬМЕНЕОФБ ЛБЛ УФТПЛХ Й ЮЙУМП, УДЕМБКФЕ УМЕДХАЭЕЕ Ч xxx_init() : args->arg_type = STRING_RESULT; args->arg_type = INT_RESULT; char **args args->args УППВЭБЕФ ЙОЖПТНБГЙА ЖХОЛГЙЙ ЙОЙГЙБМЙЪБГЙЙ ПФОПУЙФЕМШОП ПВЭЕЗП ИБТБЛФЕТБ РБТБНЕФТПЧ, У ЛПФПТЩНЙ чБЫБ ЖХОЛГЙС ВЩМБ ЧЩЪЧБОБ. дМС РПУФПСООПЗП РБТБНЕФТБ (ЛПОУФБОФЩ) i args->args[i] ХЛБЪЩЧБЕФ ОБ ЪОБЮЕОЙЕ РБТБНЕФТБ. дМС ОЕРПУФПСООПЗП РБТБНЕФТБ args->args[i] ТБЧОП 0 . рПУФПСООЩК РБТБНЕФТ РТЕДУФБЧМСЕФ УПВПК ЧЩТБЦЕОЙЕ, ЛПФПТПЕ ЙУРПМШЪХЕФ ФПМШЛП ЛПОУФБОФЩ, ФЙРБ 3 , 4*7-2 ЙМЙ SIN(3.14) . оЕРПУФПСООЩК РБТБНЕФТ РТЕДУФБЧМСЕФ УПВПК ЧЩТБЦЕОЙЕ, ЛПФПТПЕ ПВТБЭБЕФУС Л ЪОБЮЕОЙСН, ЛПФПТЩЕ НПЗХФ ЙЪНЕОСФШУС, ФЙРБ ЙНЕОЙ УФПМВГБ ЙМЙ ЖХОЛГЙК, ЛПФПТЩЕ ЧЩЪЧБОЩ У ОЕРПУФПСООЩНЙ РБТБНЕФТБНЙ. дМС ЛБЦДПЗП ПВТБЭЕОЙС ПУОПЧОПК ЖХОЛГЙЙ args->args ИТБОЙФ ЖБЛФЙЮЕУЛЙЕ РБТБНЕФТЩ, ЛПФПТЩЕ РЕТЕДБОЩ ДМС Ч ОБУФПСЭЕЕ ЧТЕНС ПВТБВБФЩЧБЕНПК УФТПЛЙ. жХОЛГЙЙ НПЗХФ ПВТБФЙФШУС Л РБТБНЕФТХ i УМЕДХАЭЙН ПВТБЪПН:

  • рБТБНЕФТ ФЙРБ STRING_RESULT , ДБООЩК ЛБЛ ХЛБЪБФЕМШ УФТПЛЙ РМАУ ДМЙОБ, РПЪЧПМСЕФ ПВТБВПФЛХ ДЧПЙЮОЩИ ДБООЩИ ЙМЙ ДБООЩИ РТПЙЪЧПМШОПК ДМЙОЩ. уПДЕТЦБОЙЕ УФТПЛЙ ДПУФХРОП ЛБЛ args->args[i] , Б ДМЙОБ УФТПЛЙ ЛБЛ args->lengths[i] . чЩ ОЕ ДПМЦОЩ УЮЙФБФШ, ЮФП УФТПЛБ ЪБЧЕТЫБЕФУС ОХМЕЧЩН УЙНЧПМПН.
  • дМС РБТБНЕФТБ ФЙРБ INT_RESULT чЩ ДПМЦОЩ РТЙЧЕУФЙ args->args[i] Л ФЙРХ long long: long long int_val; int_val = *((long long*) args->args[i]);
  • дМС РБТБНЕФТБ ФЙРБ REAL_RESULT чЩ ДПМЦОЩ РТЙЧЕУФЙ args->args[i] Л ФЙРХ double: double real_val; real_val = *((double*) args->args[i]);
unsigned long *lengths дМС ЖХОЛГЙЙ ЙОЙГЙБМЙЪБГЙЙ, НБУУЙЧ lengths ХЛБЪЩЧБЕФ НБЛУЙНБМШОХА ДМЙОХ УФТПЛЙ ДМС ЛБЦДПЗП РБТБНЕФТБ. дМС ЛБЦДПЗП ПВТБЭЕОЙС Л ПУОПЧОПК ЖХОЛГЙЙ lengths ИТБОЙФ ЖБЛФЙЮЕУЛЙЕ ДМЙОЩ МАВЩИ УФТПЛПЧЩИ РБТБНЕФТПЧ, ЛПФПТЩЕ РЕТЕДБОЩ ДМС УФТПЛЙ, ПВТБВБФЩЧБЕНПК Ч ОБУФПСЭЕЕ ЧТЕНС. дМС РБТБНЕФТПЧ ФЙРПЧ INT_RESULT ЙМЙ REAL_RESULT lengths ИТБОЙФ НБЛУЙНБМШОХА ДМЙОХ РБТБНЕФТБ (ЛБЛ ДМС ЖХОЛГЙЙ ЙОЙГЙБМЙЪБГЙЙ).

3.1.2.3 чПЪЧТБЭБЕНЩЕ ЪОБЮЕОЙС Й ПВТБВПФЛБ ПЫЙВПЛ

жХОЛГЙС ЙОЙГЙБМЙЪБГЙЙ ЧПЪЧТБФЙФ 0 , ЕУМЙ ОЙЛБЛБС ПЫЙВЛБ ОЕ РТПЙЪПЫМБ, Й 1 Ч РТПФЙЧОПН УМХЮБЕ. еУМЙ ПЫЙВЛБ РТПЙУИПДЙФ, xxx_init() ДПМЦОБ УПИТБОЙФШ УППВЭЕОЙЕ ПВ ПЫЙВЛЕ У ОХМЕЧЩН УЙНЧПМПН Ч ЛПОГЕ Ч РБТБНЕФТЕ message . уППВЭЕОЙЕ ВХДЕФ ЧПЪЧТБЭЕОП РПМШЪПЧБФЕМА. вХЖЕТ УППВЭЕОЙК ЙНЕЕФ ДМЙОХ Ч MYSQL_ERRMSG_SIZE УЙНЧПМПЧ, ОП чЩ ДПМЦОЩ РПРТПВПЧБФШ УПИТБОЙФШ УППВЭЕОЙЕ Ч 80 УЙНЧПМБИ ФБЛ, ЮФПВЩ ЬФП ХДПЧМЕФЧПТЙМП ЫЙТЙОЕ УФБОДБТФОПЗП ЬЛТБОБ ФЕТНЙОБМБ.

ъОБЮЕОЙЕ ЧПЪЧТБФБ ПУОПЧОПК ЖХОЛГЙЙ xxx() ЪБЧЙУЙФ ПФ ФЙРБ. дМС ЖХОЛГЙК ФЙРПЧ long long Й double ПОП РТЕДУФБЧМСЕФ УПВПК УПВУФЧЕООП ЖХОЛГЙПОБМШОПЕ ЪОБЮЕОЙЕ. уФТПЛПЧЩЕ ЖХОЛГЙЙ ДПМЦОЩ ЧПЪЧТБФЙФШ ХЛБЪБФЕМШ ОБ ТЕЪХМШФБФ Й УПИТБОЙФШ ДМЙОХ УФТПЛЙ Ч РБТБНЕФТБИ length . ъДЕУШ result РТЕДУФБЧМСЕФ УПВПК ВХЖЕТ ДМЙОПК Ч 255 ВБКФ. хУФБОПЧЙФЕ ЙИ Л УПДЕТЦБОЙА Й ДМЙОЕ ЪОБЮЕОЙС. оБРТЙНЕТ:

Memcpy(result, "result string", 13); *length=13;

еУМЙ чБЫЙ ЖХОЛГЙЙ УФТПЛЙ ДПМЦОЩ ЧПЪЧТБФЙФШ УФТПЛХ ДМЙООЕЕ, ЮЕН 255 ВБКФ, ТБУРТЕДЕМЙФЕ РБНСФШ ДМС ТЕЪХМШФБФБ ЮЕТЕЪ malloc() Ч ЖХОЛГЙЙ xxx_init() ЙМЙ Ч xxx() , Б ЪБФЕН ПУЧПВПДЙФЕ РБНСФШ Ч xxx_deinit() . чЩ НПЦЕФЕ УПИТБОСФШ ТБУРТЕДЕМЕООХА РБНСФШ Ч УМПФЕ ptr УФТХЛФХТЩ UDF_INIT ДМС РПЧФПТОПЗП ЙУРПМШЪПЧБОЙС Ч ВХДХЭЕН ПВТБЭЕОЙЙ xxx() . рПДТПВОПУФЙ Ч ТБЪДЕМЕ "3.1.2.1 уПЗМБЫЕОЙС П ЧЩЪПЧЕ UDF ".

юФПВЩ ХЛБЪЩЧБФШ ЪОБЮЕОЙЕ ЧПЪЧТБФБ NULL Ч ПУОПЧОПК ЖХОЛГЙЙ, ХУФБОПЧЙФЕ is_null Ч 1:

*is_null=1;

юФПВЩ ХЛБЪБФШ ЧПЪЧТБФ ПЫЙВЛЙ Ч ПУОПЧОПК ЖХОЛГЙЙ, ХУФБОПЧЙФЕ РБТБНЕФТ ПЫЙВЛЙ (error) Ч ЪОБЮЕОЙЕ 1:

*error=1;

еУМЙ xxx() ХУФБОБЧМЙЧБЕФ *error Ч 1 ДМС МАВПК УФТПЛЙ, ЖХОЛГЙПОБМШОПЕ ЪОБЮЕОЙЕ NULL ДМС ФЕЛХЭЕК УФТПЛЙ Й ДМС МАВЩИ РПУМЕДХАЭЙИ УФТПЛ, ПВТБВПФБООЩИ ЙОУФТХЛГЙЕК, Ч ЛПФПТПК ЧЩЪЩЧБМБУШ XXX() . рТЙЮЕН, xxx() ОЕ ВХДЕФ ДБЦЕ ЪБРТБЫЙЧБФШУС ДМС РПУМЕДХАЭЙИ УФТПЛ. ртйнеюбойе: ч MySQL ДП ЧЕТУЙЙ 3.22.10 чЩ ДПМЦОЩ ХУФБОПЧЙФШ *error Й *is_null:

*error=1; *is_null=1;

3.1.2.4 лПНРЙМСГЙС Й ХУФБОПЧЛБ ПРТЕДЕМСЕНЩИ РПМШЪПЧБФЕМЕН ЖХОЛГЙК

жБКМЩ, ЧЩРПМОСАЭЙЕ UDF, ДПМЦОЩ ЛПНРЙМЙТПЧБФШУС Й ХУФБОБЧМЙЧБФШУС ОБ УЕТЧЕТЕ. ьФПФ РТПГЕУУ ПРЙУБО ОЙЦЕ ДМС РТЙНЕТОПЗП UDF-ЖБКМБ udf_example.cc , ЛПФПТЩК ЧЛМАЮЕО Ч ДЙУФТЙВХФЙЧ ЙУИПДОЙЛПЧ MySQL. ьФПФ ЖБКМ УПДЕТЦЙФ УМЕДХАЭЙЕ ЖХОЛГЙЙ:

  • metaphon() ЧПЪЧТБЭБЕФ НЕФБ-УФТПЛХ ДМС УФТПЛПЧПЗП РБТБНЕФТБ. ьФП РПИПЦЕ ОБ soundex, ОП ВПМШЫЕ ЪБФПЮЕОП РПД БОЗМЙКУЛЙК.
  • myfunc_double() ЧПЪЧТБЭБЕФ УХННХ ASCII-ЪОБЮЕОЙК УЙНЧПМПЧ Ч РБТБНЕФТБИ, РПДЕМЕООХА ОБ УХННХ ДМЙО ЬФЙИ РБТБНЕФТПЧ.
  • myfunc_int() ЧПЪЧТБЭБЕФ УХННХ ДМЙО РБТБНЕФТПЧ.
  • sequence() ЧПЪЧТБФЙФ РПУМЕДПЧБФЕМШОПУФШ, ОБЮЙОБАЭХАУС У ЪБДБООПЗП ЮЙУМБ ЙМЙ У 1, ЕУМЙ ОЙЛБЛПЗП ЮЙУМБ ЪБДБОП ОЕ ВЩМП.
  • lookup() ЧПЪЧТБЭБЕФ IP-БДТЕУ.
  • reverse_lookup() ЧПЪЧТБЭБЕФ hostname ДМС IP-БДТЕУБ. жХОЛГЙС НПЦЕФ ВЩФШ ЧЩЪЧБОБ УП УФТПЛПК "xxx.xxx.xxx.xxx" ЙМЙ У 4 ЮЙУМБНЙ.

дЙОБНЙЮЕУЛЙ ЪБЗТХЦБЕНЩК ЖБКМ ДПМЦЕО ЛПНРЙМЙТПЧБФШУС ЛБЛ ТБЪДЕМСЕНЩК ПВЯЕЛФОЩК ЖБКМ, ЙУРПМШЪХС ЛПНБОДХ:

Shell> gcc -shared -o udf_example.so myfunc.cc

чЩ НПЦЕФЕ МЕЗЛП ЧЩСУОСФШ РТБЧЙМШОЩЕ РБТБНЕФТЩ ЛПНРЙМСФПТБ ДМС чБЫЕК УЙУФЕНЩ, ЪБРХУЛБС ФБЛХА ЛПНБОДХ Ч ЛБФБМПЗЕ sql чБЫЕЗП ДЕТЕЧБ ЙУИПДОЩИ ФЕЛУФПЧ MySQL:

Shell> make udf_example.o

чЩ ДПМЦОЩ ЧЩРПМОЙФШ ЛПНБОДХ ЛПНРЙМСГЙЙ, РПДПВОХА ПДОПК ЙЪ ФЕИ, ЮФП ПФПВТБЦБЕФ make , ЪБ ЙУЛМАЮЕОЙЕН ФПЗП, ЮФП чЩ ДПМЦОЩ ХДБМЙФШ ПРГЙА -c ВМЙЪЛП Л ЛПОГХ УФТПЛЙ Й ДПВБЧЙФШ -o udf_example.so Ч УБНЩК ЛПОЕГ УФТПЛЙ. оБ ОЕЛПФПТЩИ УЙУФЕНБИ ХДБМСФШ -c ОЕ ОБДП, РТПВХКФЕ.

лБЛ ФПМШЛП чЩ УЛПНРЙМЙТХЕФЕ ПВЭЕДПУФХРОЩК ПВЯЕЛФ, УПДЕТЦБЭЙК UDF, чЩ ДПМЦОЩ ХУФБОПЧЙФШ ЕЗП Й УППВЭЙФШ MySQL П ТБУЫЙТЕОЙЙ ЖХОЛГЙПОБМШОПУФЙ. лПНРЙМСГЙС ПВЭЕДПУФХРОПЗП ПВЯЕЛФБ ЙЪ udf_example.cc РТПЙЪЧПДЙФ ЖБКМ У ЙНЕОЕН udf_example.so (ФПЮОПЕ ЙНС НПЦЕФ ЙЪНЕОСФШУС ПФ РМБФЖПТНЩ Л РМБФЖПТНЕ). уЛПРЙТХКФЕ ЬФПФ ЖБКМ Ч ОЕЛПФПТЩК ЛБФБМПЗ, ЗДЕ ЙЭЕФ ЖБКМЩ ld , ОБРТЙНЕТ, Ч /usr/lib . оБ НОПЗЙИ УЙУФЕНБИ чЩ НПЦЕФЕ ХУФБОБЧМЙЧБФШ УЙУФЕНОХА РЕТЕНЕООХА LD_LIBRARY ЙМЙ LD_LIBRARY_PATH , ЮФПВЩ ХЛБЪБФШ ЛБФБМПЗ, ЗДЕ чЩ ЙНЕЕФЕ чБЫЙ ЖБКМЩ ЖХОЛГЙЙ UDF. тХЛПЧПДУФЧП ОБ dlopen УППВЭБЕФ чБН, ЛПФПТХА РЕТЕНЕООХА чЩ ДПМЦОЩ ЙУРПМШЪПЧБФШ ОБ чБЫЕК УЙУФЕНЕ. чЩ ДПМЦОЩ ХУФБОПЧЙФШ ЬФП Ч mysql.server ЙМЙ Ч safe_mysqld Й РЕТЕЪБРХУФЙФШ mysqld .

рПУМЕ ФПЗП, ЛБЛ ВЙВМЙПФЕЛБ ХУФБОПЧМЕОБ, УППВЭЙФЕ mysqld ПФОПУЙФЕМШОП ОПЧЩИ ЖХОЛГЙК ЬФЙНЙ ЛПНБОДБНЙ:

Mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so"; mysql> CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so"; mysql> CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so"; mysql> CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so"; mysql> CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";

жХОЛГЙЙ НПЗХФ ВЩФШ ХДБМЕОЩ, ЙУРПМШЪХС DROP FUNCTION:

Mysql> DROP FUNCTION metaphon; mysql> DROP FUNCTION myfunc_double; mysql> DROP FUNCTION myfunc_int; mysql> DROP FUNCTION lookup; mysql> DROP FUNCTION reverse_lookup;

йОУФТХЛГЙЙ CREATE FUNCTION Й DROP FUNCTION НПДЙЖЙГЙТХАФ УЙУФЕНОХА ФБВМЙГХ func Ч ВБЪЕ ДБООЩИ mysql . йНС ЖХОЛГЙЙ, ФЙР Й ПВЭЕДПУФХРОПЕ ВЙВМЙПФЕЮОПЕ ЙНС ВХДХФ УПИТБОЕОП Ч ФБВМЙГЕ. чЩ ДПМЦОЩ ЙНЕФШ РТЙЧЙМЕЗЙЙ insert Й delete ДМС ВБЪЩ ДБООЩИ mysql , ЮФПВЩ УПЪДБЧБФШ Й ХДБМСФШ УЧПЙ ЖХОЛГЙЙ.

чЩ ОЕ ДПМЦОЩ ЙУРПМШЪПЧБФШ CREATE FUNCTION , ЮФПВЩ ДПВБЧЙФШ ЖХОЛГЙА, ЛПФПТБС ХЦЕ ВЩМБ УПЪДБОБ. еУМЙ чЩ ДПМЦОЩ РПЧФПТОП ХУФБОПЧЙФШ ЖХОЛГЙА, УОБЮБМБ ХДБМЙФЕ ЕЕ ЮЕТЕЪ ЧЩЪПЧ DROP FUNCTION Й ЪБФЕН РПЧФПТОП ХУФБОПЧЙФЕ ЕЕ У РПНПЭША CREATE FUNCTION . чЩ ДПМЦОЩ УДЕМБФШ ЬФП, ОБРТЙНЕТ, ЕУМЙ чЩ ПФЛПНРЙМЙТПЧБМЙ ОПЧХА ЧЕТУЙА чБЫЕК ЖХОЛГЙЙ, ЮФПВЩ mysqld ПВОПЧЙМ ЙУРПМШЪХЕНХА ЙН ЧЕТУЙА. йОБЮЕ УЕТЧЕТ РТПДПМЦЙФ РТЙНЕОСФШ УФБТХА ЧЕТУЙА.

бЛФЙЧОЩЕ ЖХОЛГЙЙ ВХДХФ РЕТЕЪБЗТХЦЕОЩ РТЙ ЛБЦДПН РЕТЕЪБРХУЛЕ УЕТЧЕТБ, ЕУМЙ чЩ ОЕ ЪБРХУЛБЕФЕ mysqld У ПРГЕК --skip-grant-tables . ч ЬФПН УМХЮБЕ ЙОЙГЙБМЙЪБГЙС UDF ВХДЕФ РТПРХЭЕОБ, Б UDF-ЖХОЛГЙЙ УФБОХФ ОЕДПУФХРОЩНЙ. бЛФЙЧОБС ЖХОЛГЙС РТЕДУФБЧМСЕФ УПВПК ЖХОЛГЙА, ЪБЗТХЦЕООХА ЮЕТЕЪ CREATE FUNCTION , ОП ОЕ ХДБМЕООХА DROP FUNCTION .

3.1.3 дПВБЧМЕОЙЕ ОПЧЩИ ЧУФТПЕООЩИ ЖХОЛГЙК

рТПГЕДХТБ ДМС ДПВБЧМЕОЙС ОПЧПК ЧУФТПЕООПК ЖХОЛГЙЙ ПРЙУБОБ ОЙЦЕ. пВТБФЙФЕ ЧОЙНБОЙЕ, ЮФП чЩ ОЕ НПЦЕФЕ ДПВБЧМСФШ ЧУФТПЕООЩЕ ЖХОЛГЙЙ Л ДЧПЙЮОПНХ ДЙУФТЙВХФЙЧХ РПФПНХ, ЮФП РТПГЕДХТБ ЧЛМАЮБЕФ ЙЪНЕОЕОЙЕ ЙУИПДОПЗП ФЕЛУФБ MySQL. чЩ ДПМЦОЩ УЛПНРЙМЙТПЧБФШ MySQL УБНПУФПСФЕМШОП ЙЪ ЙУИПДОЙЛПЧ. фБЛЦЕ ПВТБФЙФЕ ЧОЙНБОЙЕ, ЮФП, ЕУМЙ чЩ НЙЗТЙТХЕФЕ ОБ ДТХЗХА ЧЕТУЙА MySQL (ОБРТЙНЕТ, ЛПЗДБ ОПЧБС ЧЕТУЙС ЧЩРХЭЕОБ), чЩ ВХДЕФЕ ДПМЦОЩ РПЧФПТЙФШ РТПГЕДХТХ У ОПЧПК ЧЕТУЙЕК.

юФПВЩ ДПВБЧЙФШ ОПЧХА ЧУФТПЕООХА ЖХОЛГЙА MySQL, ОХЦОП:

  1. дПВБЧШФЕ ПДОХ УФТПЛХ Ч ЖБКМ lex.h , ЛПФПТБС ПРТЕДЕМСЕФ ЙНС ЖХОЛГЙЙ Ч НБУУЙЧЕ sql_functions .
  2. еУМЙ ЖХОЛГЙПОБМШОЩК РТПФПФЙР РТПУФ (ВЕТЕФ ОЕ ВПМЕЕ ФТЕИ РБТБНЕФТПЧ), чЩ ДПМЦОЩ Ч lex.h ПРТЕДЕМЙФШ SYM(FUNC_ARG#) (ЪДЕУШ # СЧМСЕФУС ЮЙУМПН РБТБНЕФТПЧ) ЛБЛ ЧФПТПК РБТБНЕФТ Ч НБУУЙЧЕ sql_functions Й ДПВБЧЙФШ ЖХОЛГЙА, ЛПФПТБС УПЪДБЕФ ЖХОЛГЙПОБМШОЩК ПВЯЕЛФ, Ч item_create.cc . уНПФТЙФЕ "ABS" Й create_funcs_abs() ЛБЛ РТЙНЕТ. еУМЙ ЖХОЛГЙПОБМШОЩК РТПФПФЙР ХУМПЦОЕО (ОБРТЙНЕТ, ВЕТЕФ РЕТЕНЕООПЕ ЮЙУМП РБТБНЕФТПЧ), чЩ ДПМЦОЩ ДПВБЧЙФШ ДЧЕ УФТПЛЙ Л sql_yacc.yy . лБЦДБС ХЛБЪЩЧБЕФ УЙНЧПМ РТЕРТПГЕУУПТБ, ЛПФПТЩК yacc ДПМЦЕО ПРТЕДЕМЙФШ (ЬФП ДПМЦОП ВЩФШ ДПВБЧМЕОП Ч ОБЮБМЕ ЖБКМБ). ъБФЕН ПРТЕДЕМЙФЕ ЖХОЛГЙПОБМШОЩЕ РБТБНЕФТЩ Й ДПВБЧШФЕ ЬМЕНЕОФ У ЬФЙНЙ РБТБНЕФТБНЙ ДМС РТБЧЙМБ УЙОФБЛУЙЮЕУЛПЗП БОБМЙЪБ simple_expr . дМС РТЙНЕТБ, РТПЧЕТШФЕ ЧУЕ НЕУФПОБИПЦДЕОЙС ATAN Ч sql_yacc.yy , ЮФПВЩ ХЧЙДЕФШ, ЛБЛ ЬФП ЧЩРПМОЕОП.
  3. ч item_func.h ПВЯСЧЙФЕ ОБУМЕДПЧБОЙЕ ЛМБУУБ ЙЪ Item_num_func ЙМЙ Item_str_func , Ч ЪБЧЙУЙНПУФЙ ПФ ФПЗП, ЧПЪЧТБЭБЕФ МЙ чБЫБ ЖХОЛГЙС ЮЙУМП ЙМЙ УФТПЛХ.
  4. ч item_func.cc ДПВБЧШФЕ ПДОП ЙЪ УМЕДХАЭЙИ ПВЯСЧМЕОЙК Ч ЪБЧЙУЙНПУФЙ ПФ ФПЗП, ПРТЕДЕМСЕФЕ МЙ чЩ ЮЙУМПЧХА ЙМЙ УФТПЛПЧХА ЖХОЛГЙА: double Item_func_newname::val() longlong Item_func_newname::val_int() String *Item_func_newname::Str(String *str) еУМЙ чЩ ОБУМЕДХЕФЕ чБЫ ПВЯЕЛФ ПФ МАВПЗП ЙЪ УФБОДБТФОЩИ ЬМЕНЕОФПЧ (РПДПВОП Item_num_func , чЩ, ЧЕТПСФОП, ДПМЦОЩ ФПМШЛП ПРТЕДЕМЙФШ ПДОХ ЙЪ ЧЩЫЕХРПНСОХФЩИ ЖХОЛГЙК Й РПЪЧПМЙФШ ТПДЙФЕМШУЛПНХ ПВЯЕЛФХ ЪБВПФЙФШУС П ДТХЗЙИ ЖХОЛГЙСИ. оБРТЙНЕТ, ЛМБУУ Item_str_func ПРТЕДЕМСЕФ ЖХОЛГЙА val() , ЛПФПТБС ЧЩРПМОСЕФ atof() ОБ ЪОБЮЕОЙЙ, ЧПЪЧТБЭЕООПН::str() .
  5. чЩ ДПМЦОЩ, ЧЕТПСФОП, ФБЛЦЕ ПРТЕДЕМЙФШ УМЕДХАЭХА ПВЯЕЛФОХА ЖХОЛГЙА: void Item_func_newname::fix_length_and_dec() ьФБ ЖХОЛГЙС ДПМЦОБ РП ЛТБКОЕК НЕТЕ ЧЩЮЙУМЙФШ max_length , ЙУИПДС ЙЪ ДБООЩИ РБТБНЕФТПЧ. max_length ЪБДБЕФ НБЛУЙНБМШОПЕ ЮЙУМП УЙНЧПМПЧ, ЛПФПТПЕ ЖХОЛГЙС НПЦЕФ ЧПЪЧТБЭБФШ. ьФБ ЖХОЛГЙС ДПМЦОБ ФБЛЦЕ ХУФБОПЧЙФШ maybe_null=0 , ЕУМЙ ПУОПЧОБС ЖХОЛГЙС ОЕ НПЦЕФ ЧПЪЧТБЭБФШ ЪОБЮЕОЙЕ NULL . жХОЛГЙС НПЦЕФ РТПЧЕТЙФШ, УРПУПВЕО МЙ МАВПК ЙЪ РБТБНЕФТПЧ ЧПЪЧТБЭБФШ NULL , РТПЧЕТСС РЕТЕНЕООХА РБТБНЕФТПЧ maybe_null . чЩ НПЦЕФЕ ЙЪХЮЙФШ Item_func_mod::fix_length_and_dec Ч ЛБЮЕУФЧЕ ФЙРЙЮОПЗП РТЙНЕТБ ФПЗП, ЛБЛ ЧУЕ ЬФП УДЕМБФШ.

чУЕ ЖХОЛГЙЙ ДПМЦОЩ ВЩФШ РПФПЮОП-ВЕЪПРБУОЩНЙ (ДТХЗЙНЙ УМПЧБНЙ, ОЕ ЙУРПМШЪХКФЕ МАВЩЕ ЗМПВБМШОЩЕ ЙМЙ УФБФЙЮЕУЛЙЕ РЕТЕНЕООЩЕ Ч ЖХОЛГЙСИ ВЕЪ ФПЗП, ЮФПВЩ ЪБЭЙФЙФШ ЙИ ЮЕТЕЪ mutex).

еУМЙ чЩ ИПФЙФЕ ЧПЪЧТБЭБФШ NULL ЙЪ::val() , ::val_int() ЙМЙ::str() чЩ ДПМЦОЩ ХУФБОПЧЙФШ null_value Ч 1 Й ЧЕТОХФШ ЙЪ ЖХОЛГЙЙ 0.

дМС ПВЯЕЛФОПК ЖХОЛГЙЙ::str() ЙНЕАФУС ОЕЛПФПТЩЕ ДПРПМОЙФЕМШОЩЕ ИЙФТПУФЙ, ЛПФПТЩЕ ОБДП ЪОБФШ:

  • рБТБНЕФТ String *str ПВЕУРЕЮЙЧБЕФ ВХЖЕТ УФТПЛЙ, ЛПФПТЩК НПЦЕФ ЙУРПМШЪПЧБФШУС, ЮФПВЩ ИТБОЙФШ ТЕЪХМШФБФ. дМС РПМХЮЕОЙС ВПМШЫЕЗП ЛПМЙЮЕУФЧБ ЙОЖПТНБГЙЙ ПФОПУЙФЕМШОП ФЙРБ String ПВТБФЙФЕУШ Л ЖБКМХ sql_string.h .
  • жХОЛГЙС::str() ДПМЦОБ ЧПЪЧТБФЙФШ УФТПЛХ, ЛПФПТБС ИТБОЙФ ТЕЪХМШФБФ, ЙМЙ (char*) 0 , ЕУМЙ ТЕЪХМШФБФПН СЧМСЕФУС NULL .
  • чУЕ ФЕЛХЭЙЕ ЖХОЛГЙЙ УФТПЛЙ ОЕ ДПМЦОЩ ТБУРТЕДЕМСФШ ОЙЛБЛХА РБНСФШ, ЕУМЙ ЬФП ОЕ БВУПМАФОП ОЕПВИПДЙНП!

3.2 дПВБЧМЕОЙЕ ОПЧЩИ РТПГЕДХТ Ч MySQL

ч MySQL чЩ НПЦЕФЕ ПРТЕДЕМСФШ РТПГЕДХТХ ОБ C++, ЛПФПТБС НПЦЕФ ПВТБЭБФШУС Й ЙЪНЕОСФШ ДБООЩЕ Ч ЪБРТПУЕ РТЕЦДЕ, ЮЕН ПОЙ ПФРТБЧСФУС Л РПМШЪПЧБФЕМА. нПДЙЖЙЛБГЙС НПЦЕФ ВЩФШ ЧЩРПМОЕОБ ОБ ХТПЧОЕ УФТПЛЙ ЙМЙ GROUP BY .

бЧФПТЩ РБЛЕФБ УПЪДБМЙ РТПГЕДХТХ РТЙНЕТБ Ч MySQL Version 3.23, ЮФПВЩ РПЛБЪБФШ чБН, ЮФП ФБН НПЦЕФ ВЩФШ ЧЩРПМОЕОП.

дПРПМОЙФЕМШОП БЧФПТЩ ТЕЛПНЕОДХАФ чБН РПУНПФТЕФШ ЖБКМ mylua, ЛПФПТЩК чЩ НПЦЕФЕ ОБКФЙ Ч ЛБФБМПЗЕ Contrib. чЩ НПЦЕФЕ ЙУРПМШЪПЧБФШ СЪЩЛ LUA, ЮФПВЩ ЪБЗТХЪЙФШ РТПГЕДХТХ Ч mysqld РТСНП ЧП ЧТЕНС ЧЩРПМОЕОЙС.

3.2.1 бОБМЙЪ РТПГЕДХТ

analyse(])

ьФБ РТПГЕДХТБ ПРТЕДЕМЕОБ Ч sql/sql_analyse.cc . пОБ ЙУУМЕДХЕФ ТЕЪХМШФБФ, РПМХЮЕООЩК ЙЪ чБЫЕЗП ЪБРТПУБ, Й ЧПЪЧТБЭБЕФ БОБМЙЪ ТЕЪХМШФБФПЧ:

  • max elements (РП ХНПМЮБОЙА 256) ЪБДБЕФ НБЛУЙНБМШОПЕ ЮЙУМП ТБЪОЩИ ЪОБЮЕОЙК, ЛПФПТЩЕ analyse ЪБНЕФЙФ Ч УФПМВГЕ. ьФП ЙУРПМШЪХЕФУС, ЮФПВЩ РТПЧЕТЙФШ ПРФЙНБМШОПУФШ РТЙНЕОЕОЙС ФЙРБ ENUM .
  • max memory (РП ХНПМЮБОЙА 8192) ЪБДБЕФ НБЛУЙНХН РБНСФЙ, ЛПФПТХА analyse ДПМЦЕО ТБУРТЕДЕМЙФШ ОБ УФПМВЕГ РТЙ РПРЩФЛЕ ОБКФЙ ЧУЕ ПФМЙЮОЩЕ ЪОБЮЕОЙС.
SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE(])

3.2.2 оБРЙУБОЙЕ РТПГЕДХТ

оБ УЕЗПДОСЫОЙК ДЕОШ ЕДЙОУФЧЕООПК ДПЛХНЕОФБГЙЕК ДМС ЬФПЗП СЧМСЕФУС ЙУИПДОЩК ЛПД РБЛЕФБ.

чЩ НПЦЕФЕ ОБКФЙ ЧУА ЙОЖПТНБГЙА ПФОПУЙФЕМШОП РТПГЕДХТ, ЙУУМЕДХС ЖБКМЩ:

  • sql/sql_analyse.cc
  • sql/procedure.h
  • sql/procedure.cc
  • sql/sql_select.cc

3.3 оБЮЙОЛБ MySQL

ьФБ ЗМБЧБ ПРЙУЩЧБЕФ НОПЗП ЧЕЭЕК, ЛПФПТЩЕ чЩ ДПМЦОЩ ЪОБФШ РТЙ ТБВПФЕ ОБ ЛПДЕ MySQL. еУМЙ чЩ РМБОЙТХЕФЕ УРПУПВУФЧПЧБФШ MySQL ТБЪТБВПФЛЕ, ЙНЕФШ ДПУФХР Л ЛПДХ ПФМБЦЙЧБЕНЩИ ЧЕТУЙК ЙМЙ ИПФЙФЕ ФПМШЛП УМЕДЙФШ ЪБ ТБЪТБВПФЛПК, УМЕДХКФЕ ЛПНБОДБН Ч ТБЪДЕМЕ " ". еУМЙ чЩ ЪБЙОФЕТЕУПЧБОЩ ЧОХФТЕООЕК ПТЗБОЙЪБГЙЕК MySQL, чЩ ДПМЦОЩ ФБЛЦЕ РПДРЙУБФШУС ОБ УРЕГЙБМШОЩК УРЙУПЛ ТБУУЩМЛЙ [email protected] .

3.3.1 рПФПЛЙ Ч MySQL

уЕТЧЕТ MySQL УПЪДБЕФ УМЕДХАЭЙЕ РПФПЛЙ:

  • рПФПЛ TCP/IP-РПДЛМАЮЕОЙК ПВТБВБФЩЧБЕФ ЧУЕ РПДЛМАЮЕОЙС, ЪБРТБЫЙЧБЕФ Й УПЪДБЕФ ОПЧЩК УРЕГЙБМЙЪЙТПЧБООЩК РПФПЛ, ЮФПВЩ ПВТБВПФБФШ БЧФПТЙЪБГЙА Й ЪБРТПУЩ SQL ДМС ЛБЦДПЗП РПДЛМАЮЕОЙС.
  • ч Windows NT ЙНЕЕФУС ДТБКЧЕТ ЙНЕОПЧБООПЗП ЛБОБМБ, ЛПФПТЩК ДЕМБЕФ ФХ ЦЕ УБНХА ТБВПФХ, ЮФП Й РПФПЛ TCP/IP, ОП У ЪБРТПУБНЙ ОБ ЙНЕОПЧБООПН ЛБОБМЕ.
  • рПФПЛ УЙЗОБМБ ПВТБВБФЩЧБЕФ ЧУЕ УЙЗОБМЩ. пО ФБЛЦЕ ПВЩЮОП ПВТБВБФЩЧБЕФ ФТЕЧПЗЙ Й ЧЩЪЩЧБЕФ process_alarm() , ЮФПВЩ ЪБЧЕТЫЙФШ РПДЛМАЮЕОЙС, ЛПФПТЩЕ ВЩМЙ ОЕБЛФЙЧОЩ УМЙЫЛПН ДПМЗП.
  • еУМЙ mysqld ЛПНРЙМЙТХЕФУС У -DUSE_ALARM_THREAD , УРЕГЙБМЙЪЙТПЧБООЩК РПФПЛ, ЛПФПТЩК ПВТБВБФЩЧБЕФ ФТЕЧПЗЙ, ВХДЕФ УПЪДБО. ьФП ЙУРПМШЪХЕФУС ФПМШЛП ОБ ОЕЛПФПТЩИ УЙУФЕНБИ, ЗДЕ ЙНЕАФУС РТПВМЕНЩ У sigwait() , ЙМЙ ЕУМЙ ЕУФШ ОЕДПУФБФЛЙ Ч РТЙНЕОЕОЙЙ ЛПДБ thr_alarm() Ч РТЙЛМБДОПК РТПЗТБННЕ ВЕЪ УРЕГЙБМЙЪЙТПЧБООПЗП РПФПЛБ ПВТБВПФЛЙ УЙЗОБМБ.
  • еУМЙ ЙУРПМШЪПЧБОБ ПРГЙС --flush_time=# , ВХДЕФ УПЪДБО ЕЭЕ ПДЙО УРЕГЙБМЙЪЙТПЧБООЩК РПФПЛ, ЛПФПТЩК УВТБУЩЧБЕФ ФБВМЙГЩ ОБ ДЙУЛ.
  • лБЦДПЕ УПЕДЙОЕОЙЕ ПВТБВБФЩЧБЕФУС УЧПЙН РПФПЛПН.
  • лБЦДБС ФБВМЙГБ, ОБ ЛПФПТПК ЙУРПМШЪПЧБОБ ЙОУФТХЛГЙС INSERT DELAYED , РПМХЮБЕФ УПВУФЧЕООЩК РПФПЛ.
  • еУМЙ чЩ ЙУРПМШЪХЕФЕ --master-host , ВХДЕФ ЪБРХЭЕО РПФПЛ ТЕРМЙЛБГЙЙ, ЮФПВЩ ЮЙФБФШ Й РТЙНЕОСФШ НПДЙЖЙЛБГЙЙ У ЗМБЧОПЗП УЕТЧЕТБ.

mysqladmin processlist РПЛБЪЩЧБЕФ ФПМШЛП РПДЛМАЮЕОЙС, РПФПЛЙ ТЕРМЙЛБГЙЙ Й INSERT DELAYED .

3.3.2 оБВПТ ФЕУФПЧ MySQL

дП ОЕДБЧОЕЗП ЧТЕНЕОЙ ПУОПЧОПК ОБВПТ ФЕУФБ ВЩМ ПУОПЧБО ОБ УПУФБЧМСАЭЙИ УПВУФЧЕООПУФШ ДБООЩИ ЪБЛБЪЮЙЛБ Й РП ЬФПК РТЙЮЙОЕ ОЕ ВЩМ РХВМЙЮОП ДПУФХРЕО. еДЙОУФЧЕООЩК РХВМЙЮОП ДПУФХРОБС ЮБУФШ РТПГЕУУБ ФЕУФЙТПЧБОЙС УПУФПСМБ ЙЪ ФЕУФБ crash-me , ЬФБМПООПЗП ФЕУФБ Perl DBI/DBD, ОБИПДСЭЕЗПУС Ч ЛБФБМПЗЕ sql-bench , Й ТБЪОППВТБЪОЩИ ФЕУФПЧ, ТБЪНЕЭЕООЩИ Ч ЛБФБМПЗЕ tests . пФУХФУФЧЙЕ УФБОДБТФЙЪЙТПЧБООПЗП РХВМЙЮОП ДПУФХРОПЗП ОБВПТБ ФЕУФПЧ УДЕМБМП ФТХДОЩН ДМС РПМШЪПЧБФЕМЕК Й ТБЪТБВПФЮЙЛПЧ ФЕУФЙТПЧБОЙЕ ЛПДБ MySQL. юФПВЩ ЙУРТБЧЙФШ ЬФХ УЙФХБГЙА, БЧФПТЩ РБЛЕФБ УПЪДБМЙ УПЧЕТЫЕООП ОПЧХА УЙУФЕНХ ФЕУФПЧ, ЛПФПТБС ФЕРЕТШ ЧЛМАЮЕОБ Ч ЙУИПДОЩЕ Й ДЧПЙЮОЩЕ ДЙУФТЙВХФЙЧЩ, ОБЮЙОБС У Version 3.23.23.

фЕЛХЭЙК ОБВПТ ФЕУФПЧ ОЕ РТПЧЕТСЕФ ЧУЕ Ч MySQL, ОП ДПМЦЕО ПИЧБФЙФШ ОБЙВПМЕЕ ПЮЕЧЙДОЩЕ ПЫЙВЛЙ Ч ПВТБВПФЛБ ЛПДБ SQL, OS/library РТПВМЕНЩ Й ФЕУФЙТПЧБОЙЕ ТЕРМЙЛБГЙЙ. лПОЕЮОБС ГЕМШ УПУФПЙФ Ч ФПН, ЮФПВЩ ЙНЕФШ ФЕУФЩ, РПЛТЩЧБАЭЙЕ 100% ЛПДБ. чЩ НПЦЕФЕ РТЕДПУФБЧЙФШ ФЕУФЩ, ЛПФПТЩЕ ЙУУМЕДХАФ ЖХОЛГЙПОБМШОЩЕ ЧПЪНПЦОПУФЙ, ЛТЙФЙЮОЩЕ ДМС чБЫЕК УЙУФЕНЩ, РПУЛПМШЛХ ЬФП ЗБТБОФЙТХЕФ, ЮФП ЧУЕ ВХДХЭЙЕ ЧЩРХУЛЙ MySQL ВХДХФ ИПТПЫП ТБВПФБФШ У чБЫЙНЙ РТЙЛМБДОЩНЙ РТПЗТБННБНЙ.

3.3.2.1 ъБРХУЛ ОБВПТБ ФЕУФПЧ MySQL

уЙУФЕНБ ФЕУФБ УПУФПЙФ ЙЪ ЙОФЕТРТЕФБФПТБ СЪЩЛПЧ ФЕУФПЧ (mysqltest), УЛТЙРФБ ПВПМПЮЛЙ, ЮФПВЩ ЧЩРПМОЙФШ ЧУЕ ФЕУФЩ (mysql-test-run), ЖБЛФЙЮЕУЛЙИ УМХЮБЕЧ ФЕУФПЧ, ОБРЙУБООЩИ ОБ УРЕГЙБМШОПН СЪЩЛЕ ФЕУФПЧ Й ЙИ ПЦЙДБЕНЩИ ТЕЪХМШФБФПЧ. юФПВЩ ЧЩРПМОЙФШ ОБВПТ ФЕУФБ ОБ чБЫЕК УЙУФЕНЕ РПУМЕ РПУФТПЕОЙС, ЧЧЕДЙФЕ make test ЙМЙ mysql-test/mysql-test-run ЙЪ ЛПТОЕЧПЗП ЛБФБМПЗБ ЙУИПДОЩИ ФЕЛУФПЧ. еУМЙ чЩ ХУФБОПЧЙМЙ ДЧПЙЮОЩК ДЙУФТЙВХФЙЧ, РЕТЕКДЙФЕ Ч ЛПТЕОШ ХУФБОПЧЛЙ (ОБРТЙНЕТ, /usr/local/mysql) Й УЛПНБОДХКФЕ scripts/mysql-test-run . чУЕ ФЕУФЩ ДПМЦОЩ ЧЩРПМОЙФШУС. еУМЙ ЬФПЗП ОЕ РТПЙЪПЫМП, РТПРПВХКФЕ ЧЩСУОЙФШ РПЮЕНХ Й УППВЭЙФЕ П РТПВМЕНЕ, ЕУМЙ ЬФП ПЫЙВЛБ Ч РБЛЕФЕ MySQL. рПДТПВОПУФЙ Ч ТБЪДЕМЕ "3.3.2.3 лБЛ УППВЭБФШ П РТПВМЕНБИ Й ПЫЙВЛБИ Ч ОБВПТЕ ФЕУФПЧ MySQL ".

еУМЙ чЩ ЙНЕЕФЕ ЛПРЙА mysqld ОБ НБЫЙОЕ, ЗДЕ чЩ ИПФЙФЕ ЧЩРПМОЙФШ ОБВПТ ФЕУФПЧ, чЩ ОЕ ДПМЦОЩ ПУФБОБЧМЙЧБФШ ЕЕ, ЕУМЙ ПОБ ОЕ ЙУРПМШЪХЕФ РПТФЩ 9306 Й 9307 . еУМЙ ПДЙО ЙЪ ЬФЙИ РПТФПЧ РТЙНЕОСЕФУС, чЩ ДПМЦОЩ ПФТЕДБЛФЙТПЧБФШ mysql-test-run Й ЙЪНЕОЙФШ ЪОБЮЕОЙС ЗМБЧОПЗП ЙМЙ РПДЮЙОЕООПЗП РПТФБ Л ФПНХ, ЛПФПТПЕ СЧМСЕФУС ДПУФХРОЩН.

чЩ НПЦЕФЕ ЪБРХУФЙФШ ЙОДЙЧЙДХБМШОП ЛБЦДЩК ФЕУФ ЛПНБОДПК mysql-test/mysql-test-run test_name .

еУМЙ ПДЙО ФЕУФ УЧБМЙМУС, РТПЧЕТШФЕ ТБВПФХ mysql-test-run У ПРГЙЕК --force , ЮФПВЩ РТПЧЕТЙФШ, УВПСФ МЙ МАВЩЕ ДТХЗЙЕ ФЕУФЩ.

3.3.2.2 тБУЫЙТЕОЙЕ ОБВПТБ ФЕУФПЧ MySQL

чЩ НПЦЕФЕ ЙУРПМШЪПЧБФШ СЪЩЛ mysqltest , ЮФПВЩ РЙУБФШ чБЫЙ УПВУФЧЕООЩЕ УМХЮБЙ ФЕУФБ. л УПЦБМЕОЙА, БЧФПТЩ РБЛЕФБ ЕЭЕ ОЕ ОБРЙУБМЙ РПМОХА ДПЛХНЕОФБГЙА ДМС ОЕЗП. чЩ НПЦЕФЕ, ПДОБЛП, ТБУУНБФТЙЧБФШ ФЕЛХЭЙЕ УМХЮБЙ ФЕУФБ Й ЙУРПМШЪПЧБФШ ЙИ ЛБЛ РТЙНЕТ. уМЕДХАЭЙЕ РХОЛФЩ ДПМЦОЩ РПНПЮШ чБН:

  • фЕУФЩ ОБИПДСФУС Ч ЛБФБМПЗЕ mysql-test/t/*.test
  • уМХЮБК ФЕУФБ УПУФПЙФ ЙЪ ЪБЧЕТЫЕООПК ФПЮЛПК У ЪБРСФПК (;) ЙОУФТХЛГЙЙ Й РПДПВЕО ЧЧПДХ ЛМЙЕОФБ ЛПНБОДОПК УФТПЛЙ mysql . йОУФТХЛГЙС РП ХНПМЮБОЙА: ЪБРТПУ, ЛПФПТЩК ВХДЕФ РПУМБО УЕТЧЕТХ MySQL, ЕУМЙ ПО ОЕ ТБУРПЪОБО ЛБЛ ЧОХФТЕООСС ЛПНБОДБ (ОБРТЙНЕТ, sleep).
  • чУЕ ЪБРТПУЩ, ЛПФПТЩЕ РТПЙЪЧПДСФ ТЕЪХМШФБФЩ, ОБРТЙНЕТ, SELECT , SHOW , EXPLAIN Й РТПЮЙЕ, ОХЦОП РТЕДЧБТЙФШ ХЛБЪБОЙЕН @/path/to/result/file . жБКМ ДПМЦЕО УПДЕТЦБФШ ПЦЙДБЕНЩЕ ТЕЪХМШФБФЩ. рТПУФПК УРПУПВ ЗЕОЕТЙТПЧБФШ ЖБКМ ТЕЪХМШФБФБ УПУФПЙФ Ч ФПН, ЮФПВЩ ЧЩРПМОЙФШ mysqltest -r юФПВЩ ЧУЕ УППФЧЕФУФЧПЧБМП ХУФБОПЧЛЕ, чЩ ДПМЦОЩ РПНЕУФЙФШ чБЫЙ ЖБКМЩ ТЕЪХМШФБФБ Ч ЛБФБМПЗ mysql-test/r Й ОБЪЧБФШ ЙИ ЛБЛ test_name.result . еУМЙ ФЕУФ РТПЙЪЧПДЙФ ВПМШЫЕ, ЮЕН ПДЙО ТЕЪХМШФБФ, чЩ ДПМЦОЩ ЙУРПМШЪПЧБФШ test_name.a.result , test_name.b.result Й ФБЛ ДБМЕЕ.
  • еУМЙ ЙОУФТХЛГЙС ЧПЪЧТБЭБЕФ ПЫЙВЛХ, чЩ ДПМЦОЩ ОБ УФТПЛЕ РЕТЕД ОЕК ХЛБЪБФШ --error error-number . ъДЕУШ error-number НПЦЕФ ВЩФШ УРЙУЛПН ЧПЪНПЦОЩИ ЛПДПЧ ПЫЙВПЛ, ПФДЕМСЕНЩИ ЪБРСФЩНЙ (,).
  • еУМЙ чЩ ЪБРЙУЩЧБЕФЕ УМХЮБК ФЕУФБ ТЕРМЙЛБГЙЙ, чЩ ДПМЦОЩ Ч РЕТЧПК УФТПЛЕ ЖБКМБ ФЕУФБ РПНЕЭБФШ source include/master-slave.inc; . юФПВЩ РЕТЕЛМАЮБФШУС НЕЦДХ ЗМБЧОПК Й РПДЮЙОЕООПК УЙУФЕНБНЙ, ЙУРПМШЪХКФЕ connection master; Й connection slave; . еУМЙ чЩ ДПМЦОЩ ДЕМБФШ ЮФП-ФП ОБ БМШФЕТОБФЙЧОПН РПДЛМАЮЕОЙЙ, чЩ НПЦЕФЕ УДЕМБФШ РПДЛМАЮЕОЙЕ connection master1; ДМС ЗМБЧОПК Й connection slave1; ДМС РПДЮЙОЕООПК УЙУФЕНЩ.
  • еУМЙ чЩ ДПМЦОЩ ДЕМБФШ ЮФП-ФП Ч ГЙЛМЕ, чЩ НПЦЕФЕ ЙУРПМШЪПЧБФШ: let $1=1000; while ($1) { # чЩРПМОСЕН ЪДЕУШ ЪБРТПУ. dec $1; }
  • юФПВЩ ВЕЪДЕКУФЧПЧБФШ НЕЦДХ ЪБРТПУБНЙ, ЙУРПМШЪХКФЕ ЛПНБОДХ sleep . пОБ РПДДЕТЦЙЧБЕФ ДПМЙ УЕЛХОДЩ, ФБЛ ЮФП чЩ НПЦЕФЕ ХЛБЪБФШ sleep 1.5; , ОБРТЙНЕТ, ЮФПВЩ ВЕЪДЕКУФЧПЧБФШ 1.5 УЕЛХОДЩ.
  • юФПВЩ ЧЩРПМОСФШ РПДЮЙОЕООПЗП У ДПРПМОЙФЕМШОЩНЙ РБТБНЕФТБНЙ ДМС чБЫЕЗП УМХЮБС ФЕУФБ, РПНЕУФЙФЕ ЙИ Ч ЖПТНБФЕ ЛПНБОДОПК УФТПЛЙ Ч mysql-test/t/test_name-slave.opt . дМС ЗМБЧОПК УЙУФЕНЩ РПНЕУФЙФЕ ЙИ Ч ЖБКМ mysql-test/t/test_name-master.opt .
  • еУМЙ чЩ ЙНЕЕФЕ ЧПРТПУ ПФОПУЙФЕМШОП ОБВПТБ ФЕУФБ ЙМЙ УМХЮБК ФЕУФБ, ЛПФПТЩК НПЦЕФ РТЙЗПДЙФШУС ЧУЕН, ОБРЙЫЙФЕ ПВ ЬФПН ОБ [email protected] . рПУЛПМШЛХ УРЙУПЛ ОЕ РТЙОЙНБЕФ ЧМПЦЕОЙС, чЩ ДПМЦОЩ ЪБЛБЮБФШ РП ftp ЧУЕ ТЕМЕЧБОФОЩЕ ЖБКМЩ ОБ ftp://support.mysql.com/pub/mysql/Incoming .

3.3.2.3 лБЛ УППВЭБФШ ПВ ПЫЙВЛБИ Ч ОБВПТЕ ФЕУФПЧ MySQL

еУМЙ чБЫБ ЧЕТУЙС MySQL ОЕ ЧЩРПМОСЕФ ОБВПТ ФЕУФПЧ, чЩ ДПМЦОЩ УДЕМБФШ ФБЛ:

  • оЕ ФПТПРЙФЕУШ РПУЩМБФШ ПФЮЕФ ПВ ПЫЙВЛЕ! уОБЮБМБ ТБЪВЕТЙФЕУШ ФПМЛПН, ЮФП ФБН Х чБУ РТПЙУИПДЙФ Й РПЮЕНХ. еУМЙ ПФЮЕФ ЧУЕ-ФБЛЙ РТЙДЕФУС РПУМБФШ, РПЦБМХКУФБ, ЙУРПМШЪХКФЕ ДМС ЕЗП ЗЕОЕТБГЙЙ УЛТЙРФ mysqlbug , ЮФПВЩ ТБЪТБВПФЮЙЛЙ НПЗМЙ РПМХЮЙФШ ЙОЖПТНБГЙА ПФОПУЙФЕМШОП чБЫЕК УЙУФЕНЩ Й ЧЕТУЙЙ MySQL.
  • хДПУФПЧЕТШФЕУШ, ЮФП ЧЛМАЮЙМЙ ЧЩЧПД mysql-test-run Й УПДЕТЦБОЙЕ ЧУЕИ.reject ЖБКМПЧ Ч ЛБФБМПЗЕ mysql-test/r .
  • еУМЙ ФЕУФ ЧБМЙФУС Ч ОБВПТЕ, РТПЧЕТШФЕ, ЮФП У ОЙН ВХДЕФ РТПЙУИПДЙФШ РТЙ ОЕРПУТЕДУФЧЕООПН ЪБРХУЛЕ ЛПНБОДПК: cd mysql-test mysql-test-run --local test-name еУМЙ ЬФП ФЕТРЙФ ОЕХДБЮХ, ФП УЛПОЖЙЗХТЙТХКФЕ MySQL У ПРГЙЕК --with-debug Й ЧЩРПМОЙФЕ mysql-test-run У ПРГЙЕК --debug . еУМЙ ЬФП ФБЛЦЕ ФЕТРЙФ ОЕХДБЮХ, ЪБЛБЮБКФЕ ЖБКМ ФТБУУЙТПЧЛЙ var/tmp/master.trace ОБ ftp://support.mysql.com/pub/mysql/secret, ЮФПВЩ БЧФПТЩ НПЗМЙ ЙУУМЕДПЧБФШ ЬФП. рПЦБМХКУФБ, ОЕ ЪБВХДШФЕ ФБЛЦЕ ЧЛМАЮЙФШ РПМОПЕ ПРЙУБОЙЕ чБЫЕК УЙУФЕНЩ, ЧЕТУЙА mysqld Й РБТБНЕФТЩ ЛПНРЙМСГЙЙ.
  • рПРТПВХКФЕ ФБЛЦЕ ЧЩРПМОЙФШ mysql-test-run У ПРГЙЕК --force , ЮФПВЩ ХЧЙДЕФШ, ЙНЕЕФУС МЙ МАВПК ДТХЗПК ФЕУФ, ЛПФПТЩК ФПЦЕ ФЕТРЙФ ОЕХДБЮХ.
  • еУМЙ чЩ ЛПНРЙМЙТПЧБМЙ MySQL УБНПУФПСФЕМШОП, ЙЪХЮЙФЕ ТХЛПЧПДУФЧП ОБ РТЕДНЕФ ФПЗП, ЛБЛ ЛПНРЙМЙТПЧБФШ MySQL ОБ чБЫЕК РМБФЖПТНЕ ЙМЙ, ЮФП РТЕДРПЮФЙФЕМШОП, ЙУРПМШЪХКФЕ ПДЙО ЙЪ ЗПФПЧЩИ ДЧПЙЮОЩИ ДЙУФТЙВХФЙЧПЧ, ЛПФПТЩК ХЦЕ ПФЛПНРЙМЙТПЧБО Й НПЦЕФ ВЩФШ УЛБЮБО У http://www.mysql.com/downloads. чУЕ УФБОДБТФОЩЕ ДЧПЙЮОЩЕ ЖБКМЩ ДПМЦОЩ РТПИПДЙФШ ФЕУФЙТПЧБОЙЕ.
  • еУМЙ чЩ РПМХЮБЕФЕ ПЫЙВЛХ, РПДПВОП Result length mismatch ЙМЙ Result content mismatch , ЬФП ПЪОБЮБЕФ, ЮФП ЧЩЧПД ФЕУФБ ОЕ УППФЧЕФУФЧПЧБМ ФПЮОП ПЦЙДБЕНПНХ ЧЩЧПДХ. ьФП НПЦЕФ ВЩФШ ПЫЙВЛПК Ч MySQL, ЙМЙ ДЕМП Ч ФПН, ЮФП чБЫБ ЧЕТУЙС mysqld РТПЙЪЧПДЙФ НБМПУФШ ЙОЩЕ ТЕЪХМШФБФЩ РТЙ ОЕЛПФПТЩИ ПВУФПСФЕМШУФЧБИ. оЕХДБЮОЩЕ ТЕЪХМШФБФЩ ФЕУФБ ВХДХФ РПНЕЭЕОЩ Ч ЖБКМ У ФЕН ЦЕ УБНЩН ПУОПЧОЩН ЙНЕОЕН, ЮФП Й ЖБКМ ТЕЪХМШФБФБ, ОП У ТБУЫЙТЕОЙЕН.reject . еУМЙ чБЫ УМХЮБК ФЕУФБ ФЕТРЙФ ОЕХДБЮХ, чЩ ДПМЦОЩ УТБЧОЙФШ ДЧБ ЖБКМБ. еУМЙ чЩ ОЕ НПЦЕФЕ ХЧЙДЕФШ, ЮЕН ПОЙ ПФМЙЮБАФУС, ЙУУМЕДХКФЕ ЙИ У РПНПЭША od -c Й РТПЧЕТШФЕ ЙИ ДМЙОЩ.
  • еУМЙ ФЕУФ ФЕТРЙФ ОЕХДБЮХ РПМОПУФША, чЩ ДПМЦОЩ РТПЧЕТЙФШ ЦХТОБМЩ Ч ЛБФБМПЗЕ mysql-test/var/log ДМС ЧЩСУОЕОЙС ФПЗП, ЮФП ОЕ ФБЛ.
  • еУМЙ чЩ ЛПНРЙМЙТПЧБМЙ MySQL У ПФМБДЛПК, НПЦОП РПРТПВПЧБФШ ПФМБЦЙЧБФШ ФЕУФ ЪБРХУЛПН mysql-test-run У ПРГЙСНЙ --gdb Й/ЙМЙ --debug . рПДТПВОПУФЙ Ч ТБЪДЕМЕ "6.1.2 уПЪДБОЙЕ ЖБКМПЧ ФТБУУЙТПЧЛЙ ". еУМЙ чЩ ОЕ ЛПНРЙМЙТПЧБМЙ MySQL ДМС ПФМБДЛЙ, ЧЕТПСФОП, УФПЙФ УДЕМБФШ ЬФП. фПМШЛП ПРТЕДЕМЙФЕ РБТБНЕФТ --with-debug ДМС ЧЩЪПЧБ configure ! рПДТПВОПУФЙ Ч ТБЪДЕМЕ " ".