Использование команд
Будут установлены две команды Matlab:
MYSQL: делает общие запросы SQL SQLINSERT: вставляет записи в базу данных
Поддерживаемые системы
Этот интерфейс был протестирован на Linux с Matlab 6 и на HP-UX с Matlab 5 и 6, но он работает и на других вариантах UNIX с модификациями в Makefile. Интерфейс был также протестирован под Windows NT 4.0.
к базе данных на HOST
MYSQL('open',HOST,USER,PASSWD);
Открывает подключение к базе данных на HOST от имени пользователя USER с паролем доступа PASSWD. MYSQL('close');
Закрывает подключение к базе данных. [RESULT,AFFECTED,INSERTID]=MYSQL(QUERY);
Возвращает структуру с именами поля из запроса. [RESULT,AFFECTED,INSERTID]=MYSQL(QUERY,'fn');
Возвращает структуру с именами полей fn1,fn2,... [RESULT]=MYSQL(QUERY,'mat');
Возвращает двойную матрицу, соответствующую выводу запроса. Это нельзя использовать на нечисловых базах данных. NULL возвращен как пустая двойная матрица. Следующие типы будут возвращены как double: DECIMAL, TINY, SHORT, LONG, FLOAT, DOUBLE, LONGLONG, INT24. Все типы BLOB будут возвращены как векторы uint8. Другие типы данных будут возвращены как строки. [AFFECTED,INSERTID]=SQLINSERT (TABLE,'valuename',value,...);
Вставляет записи в базу данных SQL.
Установка
Вы должны иметь уже установленные Matlab и MySQL. Для Windows я использовал Microsoft Visual C++ 5.0, библиотеку клиентов MySQL из пакета winclients-3.22.14.zip и Cygwin GNU Make. Более поздние версии библиотеки клиентов MySQL должны работать и с VC++ 6. Для UNIX использовался GCC. Скопируйте правильную версию Makefile: cp Makefile.hpux Makefile # Для HP-UX cp Makefile.linux Makefile # Для Linux copy Makefile.win32 Makefile # Для Windows
Проверьте координаты библиотек и каталог назначения в первых строках Makefile. Затем откомпилируйте Mex: gmake
Проверьте библиотеку и инсталлируйте файлы: gmake test gmake install
Версия 1.12. Краткое описание интерфейса
Эти файлы генерируют MEX-функции Matlab, которые могут использоваться, чтобы обратиться к базе данных MySQL из пакета Matlab (разработчик: MathWorks, http://www.mathworks.com).
Оригинальный интерфейс был написан Kimmo Uutela (, http://boojum.hut.fi/~kuutela) и изменен John Fisher (). Затем он был перенесен под Windows Brian Shand (). Функции нуждаются в библиотеке mysqlclient (public domain, входит в дистрибутив MySQL).
Возможные проблемы установки
Библиотека mysqlclient должна компилироваться как position-независимый код. На HP-UX это может быть выполнено параметром компиляции +z, на Linux надо использовать параметр -fPIC.
Чтобы использовать интерфейс в Linux с Matlab 5, Вы должны иметь библиотеку libmysqlclient, совместимую с libc5. В некоторых случаях Вы можете столкнуться с необходимостью явно добавить библиотеку libgcc к библиотекам системы. Правильное имя находится с помощью locate libgcc.a.
Могут иметься проблемы с использованием различных версий MySQL DLL одновременно. Должно быть возможно использовать последнюю версию DLL с Visual C++ 5.0. При установке DLL скопирована в двоичный каталог Matlab так, чтобы она была легко доступна в пути поиска файлов, когда это необходимо.
DBI с DBD::mysql
DBI представляет собой универсальный интерфейс для многих баз данных. Это означает, что Вы можете написать скрипт, который работает с многими серверами баз данных без изменений. Вы нуждаетесь в драйвере базы данных (DBD) для каждого типа базы данных. Для MySQL этот драйвер назван DBD::mysql.
Для получения большего количества информации относительно Perl5 DBI, пожалуйста, посетите Web-страницу DBI и прочтите документацию на ней по адресу http://dbi.perl.org/docs/.
Для получения большего количества информации относительно объектно-ориентированного программирования (OOП) как оно определено в Perl5, обратитесь по адресу http://www.perl.com/pub/q/documentation.
Обратите внимание, что, если Вы хотите использовать транзакции с Perl, Вы должны иметь Msql-Mysql-modules версии 1.2216 или новее.
Интерфейс DBI
Портируемые методы DBI
connect | Устанавливает подключение к серверу. |
disconnect | Закрывает подключение к серверу. |
prepare | Готовит инструкцию SQL для выполнения. |
execute | Выполняет подготовленные инструкции. |
do | Готовит и выполняет инструкцию SQL. |
quote | Цитирует строку или значения BLOB, которые будут вставлены. |
fetchrow_array | Выбирает следующую строку как массив полей. |
fetchrow_arrayref | Выбирает следующую строку как массив ссылок на поля. |
fetchrow_hashref | Выбирает следующую строку как ссылку на hashtable. |
fetchall_arrayref | Выбирает все данные как массив массивов. |
finish | Заканчивает инструкцию и позволяет системе освободить ресурсы. |
rows | Возвращается число строк, на которые воздействовал данный запрос. |
data_sources | Возвращает массив баз данных, доступных на localhost. |
ChopBlanks | Указывает методам fetchrow_* урезать ли пробелы. |
NUM_OF_PARAMS | Число параметров в подготовленной инструкции. |
NULLABLE | Которые столбцы могут быть NULL. |
trace | Выполнить трассировку для отладки. |
MySQL-специфичные методы
insertid | Последнее занчение AUTO_INCREMENT. |
is_blob | Которые столбцы являются значениями BLOB. |
is_key | Которые столбцы являются ключами. |
is_num | Которые столбцы являются числовыми. |
is_pri_key | Которые столбцы являются первичными ключами в данной таблице. |
is_not_null | Которые столбцы не могут быть NULL. |
length | Максимально возможные размеры столбца. |
max_length | Максимальные размеры столбца, фактически представленные в результате. |
NAME | Имена столбцов. |
NUM_OF_FIELDS | Число возвращенных полей. |
table | Имена таблицы в возвращенном наборе. |
type | Все типы столбцов. |
Методы Perl описаны более подробно в следующих разделах. Переменные, используемые для значений возврата метода, имеют эти значения:
$dbh Дескриптор базы данных $sth Дескриптор оператора Statement handle $rc Код возврата (часто состояние) $rv Значение возврата (часто число строк)
Портируемые методы DBI
connect($data_source, $username, $password) Используйте метод connect, чтобы сделать подключение к базе с источником данных. Значение $data_source должно начинаться с DBI:driver_name:. Пример connect с драйвером DBD::mysql: $dbh = DBI->connect("DBI:mysql:$database", $user, $password); $dbh = DBI->connect("DBI:mysql:$database:$hostname", $user, $password); $dbh = DBI->connect("DBI:mysql:$database:$hostname:$port", $user, $password); Если имя пользователя и/или пароль не определены, DBI использует значения системных переменных DBI_USER и DBI_PASS соответственно. Если Вы не определяете hostname, по умолчанию берется localhost. Если Вы не определяете номер порта, это выставляется в порт MySQL по умолчанию (3306). Начиная с Msql-Mysql-modules Version 1.2009, значение $data_source позволяет модификаторы:
mysql_read_default_file= file_name Читать файл опций filename. mysql_read_default_group=group_name Заданная по умолчанию группа при чтении файла опций, обычно это группа [client]. Если опция mysql_read_default_group определена, группой в файле опций будет [group_name]. mysql_compression=1 Использовать сжатую связь между пользователем и сервером (доступно только в MySQL Version 3.22.3 или позже). mysql_socket=/path/to/socket Определяет имя Unix-сокета, который используется, чтобы подключиться к серверу (доступно только в MySQL Version 3.21.15 или позже).Может быть задано много модификаторов каждому должна предшествовать точка с запятой. Например, если Вы хотите избежать прямого указания имени пользователя и пароля в скрипте DBI, Вы можете брать их из пользовательского файла опций ~/.my.cnf переделав connect следующим образом: $dbh = DBI->connect("DBI:mysql:$database" . ";mysql_read_default_file=$ENV{HOME}/.my.cnf", $user, $password); Это обращение будет читать параметры, определенные для группы [client] в файле опций. Если Вы хотите сделать то же самое, но опции брать из секции [perl], Вы могли бы использовать это: $dbh = DBI->connect("DBI:mysql:$database" . ";mysql_read_default_file=$ENV{HOME}/.my.cnf" . ";mysql_read_default_group=perl", $user, $password);
disconnect Метод disconnect отсоединяет дескриптор базы данных от собственно базы данных. Это надлежит сделать перед завершением программы: $rc = $dbh->disconnect;
prepare($statement) Готовит инструкцию SQL для выполнения ядром базы данных и возвращает операторный дескриптор ($sth), который Вы можете использовать, чтобы вызвать метод execute. Обычно Вы обрабатываете инструкции SELECT (а также SELECT-подобные инструкции, вроде SHOW, DESCRIBE и EXPLAIN) посредством prepare и execute. Например так: $sth = $dbh->prepare($statement) or die "Can't prepare $statement: $dbh->errstr\n";
execute Метод execute выполняет подготовленную инструкцию. Для инструкций не-SELECT, execute возвращает число строк, на которые воздействовал оператор. Если ни на какие строки метод не воздействовал, он вернет 0E0, который Perl обрабатывает как ноль, но расценивает как истину. Если происходит ошибка, execute вернет undef. Для инструкций SELECT execute только запускает запрос SQL в базе данных. Вы должны использовать один из методов fetch_*, описанных ниже, чтобы получить сами данные. Пример: $rv = $sth->execute or die "can't execute the query: $sth->errstr;
do($statement) Метод do готовит и выполняет инструкцию SQL и возвращает число строк , на которые воздействовал оператор. Если ни на какие строки метод не воздействовал, он вернет 0E0, который Perl обрабатывает как ноль, но расценивает как истину. Если происходит ошибка, do вернет undef. Этот метод вообще используется для инструкций не-SELECT, которые не могут быть подготовлены заранее (из-за ограничений драйвера) или тех инструкций, которые не должны быть выполнены больше, чем однажды (вставки, удаления и т.п.). Например: $rv = $dbh->do($statement) or die "Can't execute $statement: $dbh- >errstr\n"; Вообще инструкция do НАМНОГО быстрее, чем prepare/execute для инструкций, которые не содержат параметров. quote($string) Метод quote используется, чтобы обойти любые специальные символы, содержащиеся в строке, и добавить требуемые внешние метки цитирования. Конкретный пример: $sql = $dbh->quote($string)
fetchrow_array Этот метод выбирает следующую строку данных и возвращает ее как массив значений полей. Пример: while(@row = $sth->fetchrow_array) { print qw($row[0]\t$row[1]\t$row[2]\n); }
fetchrow_arrayref Этот метод выбирает следующую строку данных и возвращает ее как ссылку на массив значений полей. Пример: while($row_ref = $sth->fetchrow_arrayref) { print qw($row_ref->[0]\t$row_ref->[1]\t$row_ref->[2]\n); }
fetchrow_hashref Этот метод выбирает строку данных и возвращает ссылку на хэш-таблицу, содержащую пары имя/значение поля. Этот метод не столь эффективен как использование ссылок на массив, как показывается выше. Пример: while($hash_ref = $sth->fetchrow_hashref) { print qw($hash_ref->{firstname}\t$hash_ref->{lastname}\t\ $hash_ref-> title}\n); }
fetchall_arrayref Этот метод используется, чтобы получить все данные (строки), которые будут возвращены из инструкции SQL. Это возвращает ссылку на массив, хранящий ссылки на массивы для каждой строки. Вы обращаетесь к ним или печатаете данные, используя вложенный цикл. Пример: my $table = $sth->fetchall_arrayref or die "$sth->errstr\n"; my($i, $j); for $i (0 .. $#{$table}) { for $j (0 .. $#{$table->[$i]}) { print "$table->[$i][$j]\t"; } print "\n"; }
finish Указывает максимальное количество данных, которое будет выбрано из этого операторного дескриптора. Вы вызываете этот метод, чтобы освободить операторный дескриптор и любые ресурсы системы, связанные с этим. Пример: $rc = $sth->finish;
rows Возвращает число измененных последней командой строк (возможно, удаленных, а не модифицированных). Это обычно используется после того, как выполнена команда не-SELECT через execute. Пример: $rv = $sth->rows;
NULLABLE Возвращает ссылку на массив булевых значений: для каждого элемента массива значение TRUE указывает, что этот столбец может содержать значение NULL. Пример: $null_possible = $sth->{NULLABLE};
NUM_OF_FIELDS Этот атрибут указывает число полей, возвращенных инструкциями SELECT или SHOW FIELDS. Вы можете использовать это для проверки, возвратила ли инструкция результат: нулевое значение указывает на инструкцию не-SELECT, типа INSERT, DELETE или UPDATE. Например: $nr_of_fields = $sth->{NUM_OF_FIELDS};
data_sources($driver_name) Этот метод возвращает массив, содержащий имена баз данных, доступных серверу MySQL на машине localhost. Например: @dbs = DBI->data_sources("mysql");
ChopBlanks Этот атрибут определяет, уберут ли методы fetchrow_* конечные пробелы из возвращенных ими значений. Пример: $sth->{'ChopBlanks'} =1;
trace($trace_level)
trace($trace_level, $trace_filename) Метод trace включает или отключает трассировку. Когда он вызывается как метод класса DBI, это воздействует на трассировку для всех дескрипторов. Когда он вызывается как метод базы данных или инструкции, это воздействует на трассировку для данного дескриптора и любых будущих потомков дескриптора. Установка $trace_level равным 2 обеспечивает детализированную информацию. Установка $trace_level в 0 отключает трассировку. Вывод идет на стандартный вывод ошибки по умолчанию. Если $trace_filename определен, файл будет открыт в режиме дополнения, и вывод для всех прослеженных дескрипторов будет записан в этот файл. Например: # Трассировать все DBI->trace(2); # Регистрировать все в /tmp/dbi.out DBI->trace(2,"/tmp/dbi.out"); # Трассировать этот дескриптор базы данных $dth->trace(2); # Трассировать этот операторный дескриптор $sth->trace(2);Вы можете также допускать трассировку DBI, устанавливая системную переменную DBI_TRACE. Установка ее к числовому значению эквивалентна вызову DBI->(value). Установка ее к имени пути эквивалентна вызову DBI->(2,value).
MySQL-специфичные методы
Методы, показанные ниже, MySQL-специфические, а не часть стандарта DBI. Несколько из них теперь осуждаются: is_blob, is_key, is_num, is_pri_key, is_not_null, length, max_length и table. Где существуют варианты в стандарте DBI, они обязательно отмечены ниже:
insertid Если Вы используете свойство MySQL AUTO_INCREMENT, новые значения будут сохранены здесь. Пример: $new_id = $sth->{insertid}; Как вариант, Вы можете использовать $dbh->{'mysql_insertid'}. is_blob Возвращает ссылку на массив булевых значений: для каждого элемента массива, значение TRUE указывает, что соответствующий столбец имеет тип BLOB. Так, например: $keys = $sth->{is_blob};
is_key Возвращает ссылку на массив булевых значений: для каждого элемента массива, значение TRUE указывает, что соответствующий столбец является ключом (не всегда первичным). Например: $keys = $sth->{is_key};
is_num Возвращает ссылку на массив булевых значений: для каждого элемента массива, значение TRUE указывает, что соответствующий столбец хранит только числовые значения. Пример: $nums = $sth->{is_num};
is_pri_key Возвращает ссылку на массив булевых значений: для каждого элемента массива, значение TRUE указывает, что соответствующий столбец является первичным ключом. Пример: $pri_keys = $sth->{is_pri_key};
is_not_null Возвращает ссылку на массив булевых значений: для каждого элемента массива, значение FALSE указывает, что соответствующий столбец может хранить (но не обязательно хранит в настоящий момент) значения NULL: $not_nulls = $sth->{is_not_null}; Метод is_not_null осуждается, предпочтительно использовать атрибут NULLABLE (описанный выше) потому, что это стандарт DBI. length
max_length Каждый из этих методов возвращает ссылку на массив размеров столбца. Массив length указывает максимальные возможные размеры, которые каждый столбец может иметь (как объявлено в описании таблицы). Массив max_length указывает максимальные размеры, фактически представленные в таблице. Пример: $lengths = $sth->{length}; $max_lengths = $sth->{max_length};
NAME Возвращает ссылку на массив имен столбцов. Пример: $names = $sth->{NAME};
table Возвращает ссылку на массив имен таблиц. Пример: $tables = $sth->{table};
type Возвращает ссылку на массив типов столбцов. Пример: $types = $sth->{type};
MySQL Perl API
Этот раздел документирует интерфейс Perl DBI. Вышеупомянутый интерфейс ранее был назван mysqlperl. Ныне рекомендуемым является DBI/DBD, так что mysqlperl здесь не рассматривается.
Подробности по DBI/DBD
Вы можете использовать команду perldoc, чтобы получить большее количество информации относительно DBI:
perldoc DBI perldoc DBI::FAQ perldoc DBD::mysql
Вы можете также использовать инструментальные средства pod2man, pod2html и им подобные, чтобы транслировать справочник к другим форматам.
Вы можете находить последнюю информацию по DBI на Web-странице DBI по адресу http://dbi.perl.org/docs/.
Проблемы с интерфейсом Perl DBI/DBD
Если Perl сообщает, что не может найти модуль ../mysql/mysql.so, то проблема, вероятно, в том что Perl не может найти общедоступную библиотеку libmysqlclient.so.
Вы можете исправить это любым из следующих методов:
Откомпилируйте дистрибутив Msql-Mysql-modules командой perl Makefile.PL -static -config вместо perl Makefile.PL. Скопируйте libmysqlclient.so в каталог, где размещены другие Ваши общедоступные библиотеки (вероятно, это /usr/lib или /lib). Под Linux Вы можете добавлять имя пути каталога, где размещен libmysqlclient.so в файл /etc/ld.so.conf. Добавьте имя пути каталога, где надо искать файл libmysqlclient.so к системной переменной LD_RUN_PATH.
Если Вы получаете следующие ошибки из DBD-mysql, Вы, вероятно, используете gcc (или используете старый двоичный дистрибутив, собранный с помощью gcc):
/usr/bin/perl: can't resolve symbol '__moddi3' /usr/bin/perl: can't resolve symbol '__divdi3'
Добавьте -L/usr/lib/gcc-lib/... -lgcc к команде компоновки, когда библиотека mysql.so собрана (проверьте вывод из make для mysql.so, когда Вы компилируете клиента Perl). Опция -L должна определить имя пути каталога, где файл libgcc.a размещен на Вашей системе.
Другой причиой этой проблемы может быть то, что Perl и MySQL не вместе компилируются gcc. В этом случае, Вы можете устранить несоответствие, компилируя оба пакета gcc.
Если Вы получаете следующую ошибку из Msql-Mysql-modules, когда Вы выполняете тесты: t/00base............install_driver(mysql) failed: Can't load '../blib/arch/auto/DBD/mysql/mysql.so' for module DBD::mysql: ../blib/arch/auto/DBD/mysql/mysql.so: undefined symbol: uncompress at /usr/lib/perl5/5.00503/i586-linux/DynaLoader.pm line 169.
Это означает, что Вы должны включить библиотеку сжатия -lz в строку компновки. Это может сделать следующее изменение в файле lib/DBD/mysql/Install.pm: $sysliblist .= " -lm"; надо поменять на $sysliblist .= " -lm -lz";
После этого, Вы ДОЛЖНЫ выполнить make realclean и затем продолжить установку с самого начала.
Если Вы хотите использовать Perl- модуль на системе, которая не поддерживает динамическую связь (подобно SCO), Вы можете сгенерировать статическую версию Perl, которая включает DBI и DBD-mysql. Соберите версию Perl с модулем DBI и установите поверх текущей версии Perl. Затем Вы используете это, чтобы сформировать версию Perl, которая дополнительно имеет встроенный код DBD, и вот ее-то и надо установить как окончательную.
На SCO Вы должны иметь следующий набор системных переменных:
shell> LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib: /usr/progressive/lib или shell> LD_LIBRARY_PATH=/usr/lib:/lib:/usr/local/lib: /usr/ccs/lib:/usr/progressive/lib:/usr/skunk/lib shell> LIBPATH=/usr/lib:/lib:/usr/local/lib:/usr/ccs/lib: /usr/progressive/lib:/usr/skunk/lib shell> MANPATH=scohelp:/usr/man:/usr/local1/man: /usr/local/man:/usr/skunk/man:
Сначала, создайте Perl, который включает статически связанный DBI, применяя эти команды в каталоге, где размещен Ваш дистрибутив пакета DBI:
shell> perl Makefile.PL -static -config shell> make shell> make install shell> make perl
Затем Вы должны установить новый Perl. Вывод из make perl укажет точную команду make, которую Вы должны выполнить, чтобы осуществить установку. На SCO это make -f Makefile.aperl inst_perl MAP_TARGET=perl.
Затем используйте только что созданный Perl, чтобы создать другой Perl, который также включает и статически связанный модуль DBD::mysql этими командами в каталоге, где размещен Ваш дистрибутив Msql-Mysql-modules:
shell> perl Makefile.PL -static -config shell> make shell> make install shell> make perl
В заключение Вы должны установить этот новый Perl. Снова вывод из команды make perl указывает команду, которую Вам надлежит использовать для выполнения установки.
Установка ActiveState Perl под Windows
Чтобы установить модуль MySQL DBD под ActiveState Perl под Windows, Вы должны сделать следующее:
Скачать ActiveState Perl с http://www.activestate.com/Products/ActivePerl/index.html и установить. Открыть DOS shell. Если надо, настроить переменную HTTP_proxy. Например, попробуйте так: set HTTP_proxy=my.proxy.com:3128
Запустите программу PPM: C:\> c:\perl\bin\ppm.pl
Если этого еще не сделано, поставьте модуль DBI: ppm> install DBI
Если все в порядке, выполните команду: install ftp://ftp.de.uu.net/pub/CPAN/authors/id/JWIED/DBD-mysql-1.2212.x86.ppd
Вышеупомянутое должно работать по крайней мере с ActiveState Perl Version 5.6.
Если Вы не можете заставить это работать, Вы должны взамен установить драйвер MyODBC и соединяться с сервером MySQL через ODBC: use DBI; $dbh=DBI->connect("DBI:ODBC:$dsn","$user","$password") die "Got error $DBI::errstr when connecting to $dsn\n";
Установка дистрибутива MySQL Perl под Windows
Дистрибутив MySQL Perl включает в себя DBI, DBD:MySQL и DBD:ODBC.
Скачайте Perl для Windows с http://dev.mysql.com/downloads/.
Распакуйте командой Unzip на диск C:, чтобы получился каталог вида C:\PERL. Добавьте каталог C:\PERL\BIN в переменную path. Добавьте туда же каталог C:\PERL\BIN\MSWIN32-x86-thread или C:\PERL\BIN\MSWIN32-x86. Протестируйте работоспособность perl выполнением команды perl -v в DOS shell.
Установка Perl на Unix
Perl-поддержка для MySQL обеспечивается посредством интерфейса пользователя DBI/DBD. Код пользователя Perl DBD/DBI требует Perl Version 5.004 или выше. Интерфейс не будет работать, если Вы имеете старую версию!
MySQL Perl-поддержка также требует, чтобы Вы установили MySQL-поддержку программирования пользователя. Если Вы установили MySQL из файлов RPM, программы пользователя находятся в клиентском RPM, но поддержка программирования пользователя находится в RPM для разработчика. Удостоверьтесь, что Вы в самом деле установили последний RPM.
Начиная с Version 3.22.8, поддержка Perl поставляется отдельно от главного дистрибутива MySQL. Если Вы хотите устанавливать поддержку Perl, нужные файлы можно найти на http://www.mysql.com/Downloads/Contrib.
Дистрибутивы Perl поставляются как сжатые архивы в формате tar и имеют имена подобные MODULE-VERSION.tar.gz, где MODULE представляет собой имя модуля, а VERSION задает номер версии. Вы должны получить пакеты Data-Dumper, DBI и Msql-Mysql-modules и устанавливать их в этом порядке. Процедура установки показывается ниже. Показанный пример подходит для модуля Data-Dumper, но процедура та же самая для всех трех нужных Вам модулей:
Распакуйте дистрибутив в текущий каталог: shell> gunzip < Data-Dumper-VERSION.tar.gz | tar xvf - Эта команда создаст каталог под именем Data-Dumper-VERSION. Теперь перейдите в каталог распакованного дистрибутива: shell> cd Data-Dumper-VERSION
Сконфигурируйте и откомпилируйте дистрибутив: shell> perl Makefile.PL shell> make shell> make test shell> make install
Команда make test важна потому, что она проверяет что модуль работает. Обратите внимание, что когда Вы выполняете эту команду в течение установки Msql-Mysql-modules, чтобы проверить код интерфейса, сервер MySQL должен работать, или тест будет терпеть неудачу.
Стоит пересобрать и повторно установить Msql-Mysql-modules всякий раз, когда Вы устанавливаете новый выпуск MySQL, особенно, если Вы обращаете внимание на нехорошие признаки типа того, что все Ваши скрипты DBI после апгрейда MySQL падают.
Если Вы не имеете права установить модули Perl в системный каталог, или чтобы установить локальные модули Perl, следующая ссылка может помочь:
http://www.bluehill.com/support/perl_modules.html
Смотрите под заголовком Installing New Modules that Require Locally Installed Modules.
Соглашения по вызову 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, чтобы использовать или освободить память.
Запуск набора тестов MySQL
Система теста состоит из интерпретатора языков тестов (mysqltest), скрипта оболочки, чтобы выполнить все тесты (mysql-test-run), фактических случаев тестов, написанных на специальном языке тестов и их ожидаемых результатов. Чтобы выполнить набор теста на Вашей системе после построения, введите make test или mysql-test/mysql-test-run из корневого каталога исходных текстов. Если Вы установили двоичный дистрибутив, перейдите в корень установки (например, /usr/local/mysql) и скомандуйте scripts/mysql-test-run. Все тесты должны выполниться. Если этого не произошло, пропобуйте выяснить почему и сообщите о проблеме, если это ошибка в пакете MySQL.
Если Вы имеете копию mysqld на машине, где Вы хотите выполнить набор тестов, Вы не должны останавливать ее, если она не использует порты 9306 и 9307. Если один из этих портов применяется, Вы должны отредактировать mysql-test-run и изменить значения главного или подчиненного порта к тому, которое является доступным.
Вы можете запустить индивидуально каждый тест командой mysql-test/mysql-test-run test_name.
Если один тест свалился, проверьте работу mysql-test-run с опцией --force, чтобы проверить, сбоят ли любые другие тесты.
Обработка параметров
Параметр 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[0] != STRING_RESULT args->arg_type[1] != INT_RESULT) { strcpy(message,"XXX() requires a string and an integer"); return 1; } Вы можете использовать функцию инициализации, чтобы установить элементы arg_type к типам, которые Вы хотите получить. Это заставляет MySQL привести параметры к тем типам для каждого обращения к xxx(). Например, чтобы определить первые два элемента как строку и число, сделайте следующее в xxx_init(): args->arg_type[0] = STRING_RESULT; args->arg_type[1] = 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 хранит максимальную длину параметра (как для функции инициализации).
Расширение набора тестов MySQL
Вы можете использовать язык mysqltest, чтобы писать Ваши собственные случаи теста. К сожалению, авторы пакета еще не написали полную документацию для него. Вы можете, однако, рассматривать текущие случаи теста и использовать их как пример. Следующие пункты должны помочь Вам:
Тесты находятся в каталоге mysql-test/t/*.test Случай теста состоит из завершенной точкой с запятой (;) инструкции и подобен вводу клиента командной строки mysql. Инструкция по умолчанию: запрос, который будет послан серверу MySQL, если он не распознан как внутренняя команда (например, sleep). Все запросы, которые производят результаты, например, SELECT, SHOW, EXPLAIN и прочие, нужно предварить указанием @/path/to/result/file. Файл должен содержать ожидаемые результаты. Простой способ генерировать файл результата состоит в том, чтобы выполнить mysqltest -r < t/test-case-name.test из каталога mysql-test, а затем отредактировать сгенерированные файлы результата, если необходимо скорректировать их к ожидаемому выводу. В этом случае будьте очень осторожны относительно добавления или удаления любых невидимых символов. Если Вы должны вставить строку, удостоверьтесь, что поля отделяются позициями табуляции, и имеется табуляция в конце. Вы можете использовать od -c, чтобы удостовериться, что Ваш текстовый редактор не добавляет что-нибудь неожиданное в течение процесса редактирования. Чтобы все соответствовало установке, Вы должны поместить Ваши файлы результата в каталог 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.3;, например, чтобы бездействовать 1.3 секунды. Чтобы выполнять подчиненного с дополнительными параметрами для Вашего случая теста, поместите их в формате командной строки в mysql-test/t/test_name-slave.opt. Для главной системы поместите их в файл mysql-test/t/test_name-master.opt. Если Вы имеете вопрос относительно набора теста или случай теста, который может пригодиться всем, напишите об этом на internals@lists.mysql.com. Поскольку список не принимает вложения, Вы должны закачать по ftp все релевантные файлы на ftp://support.mysql.com/pub/mysql/Incoming.
Как сообщать об ошибках в наборе тестов 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. Если Вы не компилировали MySQL для отладки, вероятно, стоит сделать это. Только определите параметр --with-debug для вызова configure!
Возвращаемые значения и обработка ошибок
Функция инициализации возвратит 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().
Чтобы указывать значение возврата 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;
Компиляция и установка определяемых пользователем функций
Файлы, выполняющие UDF, должны компилироваться и устанавливаться на сервере. Этот процесс описан ниже для примерного UDF-файла udf_example.cc, который включен в дистрибутив исходников MySQL. Этот файл содержит следующие функции:
metaphon() возвращает мета-строку для строкового параметра. Это похоже на soundex, но больше заточено под английский. myfunc_double() возвращает сумму ASCII-значений символов в параметрах, поделенную на сумму длин этих параметров. myfunc_int() возвращает сумму длин параметров. sequence([const int]) возвратит последовательность, начинающуюся с заданного числа или с 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.
Анализ процедур
analyse([max elements,[max memory]])
Эта процедура определена в sql/sql_analyse.cc. Она исследует результат, полученный из Вашего запроса, и возвращает анализ результатов:
max elements (по умолчанию 256) задает максимальное число разных значений, которые analyse заметит в столбце. Это используется, чтобы проверить оптимальность применения типа ENUM.
max memory (по умолчанию 8192) задает максимум памяти, которую analyse должен распределить на столбец при попытке найти все отличные значения.
SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max elements,[max memory]])
Добавление новой функции, определяемой пользователем
Для работы механизма 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().
Добавление новых функций в MySQL
Есть два способа добавить новую функцию в MySQL:
Вы можете добавить функцию через механизм определяемых пользователем функций (user-definable function, UDF). Они добавляются динамически, используя команды CREATE FUNCTION и DROP FUNCTION. Вы можете добавить функцию как внутреннюю в MySQL. Такие функции компилируются прямо внутрь сервера mysqld и становятся доступными на постоянной основе.
Каждый метод имеет свои проблемы:
Если Вы пишете определяемую пользователем функцию, Вы должны установить объектный файл в дополнение к серверу. Если Вы компилируете Вашу функцию прямо в сервер, Вы не должны делать этого. Вы можете добавлять UDF к двоичному дистрибутиву MySQL. Встроенные функции требуют, чтобы Вы изменили исходники. Если Вы обновляете MySQL, Вы можете продолжать использовать Ваш предварительно установленный UDF. Для встроенных функций Вы должны повторить модификации каждый раз, когда Вы делаете апгрейд.
Независимо от метода, который Вы используете, чтобы добавить новые функции, они могут использоваться точно так же как местные функции типа ABS() или SOUNDEX().
Добавление новых процедур в MySQL
В MySQL Вы можете определять процедуру на C++, которая может обращаться и изменять данные в запросе прежде, чем они отправятся к пользователю. Модификация может быть выполнена на уровне строки или GROUP BY.
Авторы пакета создали процедуру примера в MySQL Version 3.23, чтобы показать Вам, что там может быть выполнено.
Дополнительно авторы рекомендуют Вам посмотреть файл mylua, который Вы можете найти в каталоге Contrib. Вы можете использовать язык LUA, чтобы загрузить процедуру в mysqld прямо во время выполнения.
Добавление новых встроенных функций
Процедура для добавления новой встроенной функции описана ниже. Обратите внимание, что Вы не можете добавлять встроенные функции к двоичному дистрибутиву потому, что процедура включает изменение исходного текста MySQL. Вы должны скомпилировать MySQL самостоятельно из исходников. Также обратите внимание, что, если Вы мигрируете на другую версию MySQL (например, когда новая версия выпущена), Вы будете должны повторить процедуру с новой версией.
Чтобы добавить новую встроенную функцию MySQL, нужно:
Добавьте одну строку в файл lex.h, которая определяет имя функции в массиве sql_functions[]. Если функциональный прототип прост (берет не более трех параметров), Вы должны в lex.h определить SYM(FUNC_ARG#) (здесь # является числом параметров) как второй параметр в массиве sql_functions[] и добавить функцию, которая создает функциональный объект, в item_create.cc. Смотрите "ABS" и create_funcs_abs() как пример. Если функциональный прототип усложнен (например, берет переменное число параметров), Вы должны добавить две строки к sql_yacc.yy. Каждая указывает символ препроцессора, который yacc должен определить (это должно быть добавлено в начале файла). Затем определите функциональные параметры и добавьте элемент с этими параметрами для правила синтаксического анализа simple_expr. Для примера, проверьте все местонахождения ATAN в sql_yacc.yy, чтобы увидеть, как это выполнено. В item_func.h объявите наследование класса из Item_num_func или Item_str_func, в зависимости от того, возвращает ли Ваша функция число или строку. В 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(). Вы должны, вероятно, также определить следующую объектную функцию: 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. Все текущие функции строки не должны распределять никакую память, если это не абсолютно необходимо!
Набор тестов MySQL
До недавнего времени основной набор теста был основан на составляющих собственность данных заказчика и по этой причине не был публично доступен. Единственный публично доступная часть процесса тестирования состояла из теста crash-me, эталонного теста Perl DBI/DBD, находящегося в каталоге sql-bench, и разнообразных тестов, размещенных в каталоге tests. Отсутствие стандартизированного публично доступного набора тестов сделало трудным для пользователей и разработчиков тестирование кода MySQL. Чтобы исправить эту ситуацию, авторы пакета создали совершенно новую систему тестов, которая теперь включена в исходные и двоичные дистрибутивы, начиная с Version 3.23.29.
Текущий набор тестов не проверяет все в MySQL, но должен охватить наиболее очевидные ошибки в обработка кода SQL, OS/library проблемы и тестирование репликации. Конечная цель состоит в том, чтобы иметь тесты, покрывающие 100% кода. Вы можете предоставить тесты, которые исследуют функциональные возможности, критичные для Вашей системы, поскольку это гарантирует, что все будущие выпуски MySQL будут хорошо работать с Вашими прикладными программами.
Начинка MySQL
Эта глава описывает много вещей, которые Вы должны знать при работе на коде MySQL. Если Вы планируете способствовать MySQL разработке, иметь доступ к коду отлаживаемых версий или хотите только следить за разработкой, поставьте дерево исходников для разработки. Если Вы заинтересованы внутренней организацией MySQL, Вы должны также подписаться на специальный список рассылки internals@lists.mysql.com.
Написание процедур
На сегодняшний день единственной документацией для этого является исходный код пакета.
Вы можете найти всю информацию относительно процедур, исследуя файлы:
sql/sql_analyse.cc sql/procedure.h sql/procedure.cc sql/sql_select.cc
Потоки в 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.
Синтаксис CREATE FUNCTION/DROP FUNCTION
CREATE [AGGREGATE] 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.
Для работы механизма UDF функции должны быть написаны на C или C++, Ваша операционная система должна поддерживать динамическую загрузку, и mysqld должен быть откомпилирован динамически (не статически).
Использование данного интерфейса
Имена методов базируются на C API без префикса mysql_. Если метод породил некую ошибку, возникает исключительная ситуация MysqlError. Загрузка модуля mysql выполняется указанием require "mysql".
Класс Mysql. Методы:
init()
Используется для Mysql#options() real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, sock=nil, flag=nil)
Псевдонимы: connect(), new() escape_string(str)
Псевдоним: quote() get_client_info()
Псевдоним: client_info() debug(str)
Объектные методы:
options(opt, val=nil)
real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, sock=nil, flag=nil)
Псевдоним: connect() affected_rows() change_user(user=nil, passwd=nil, db=nil) character_set_name() close() create_db(db) dump_debug_info() drop_db(db) errno() error() escape_string(str)
Псевдоним: quote() field_count() get_host_info()
Псевдоним: host_info() get_proto_info()
Псевдоним: proto_info() get_server_info()
Псевдоним: server_info() info() insert_id() kill(id) list_dbs(db=nil) list_fields(table, field=nil) list_processes() list_tables(table=nil) ping() query(q) refresh(r) reload() select_db(db) shutdown() stat() store_result() thread_id() use_result()
Объектные переменные:
query_with_result
Если true, query() действует как store_result() и возвращает объект MysqlRes. Значение по умолчанию: true.
Класс MysqlRes. Методы:
free() data_seek(offset) fetch_field() fetch_fields() fetch_field_direct(fieldnr) fetch_lengths() fetch_row() fetch_hash(with_table=false) field_seek(offset) field_tell() num_fields() num_rows() row_seek(offset) row_tell()
Итераторы:
each() {|x| ...}
x представляет собой массив значений столбца. each_hash(with_table=false) {|x| ...}
x представляет собой хэш значений столбца, а ключ является именем столбца.
Класс MysqlField. Объектные переменные (только для чтения):
name table def type length max_length flags decimals
Объектные методы в классе:
hash(), inspect()
Возвращает строку в формате "#".
Класс MysqlError. Объектные переменные (только для чтения):
error, errno
Это MySQL Ruby API. Он
Это MySQL Ruby API. Он отвечает за реализацию ряда функций, аналогичных MySQL C API.
Для исправной работы интерфейса требуются, как минимум:
MySQL 3.23.10+ Ruby 1.4.5+
Автор: TOMITA Masahiro (, http://www.tmtm.org/mysql).
Порядок установки интерфейса
Сначала введите команды: # ruby extconf.rb # make
Скрипт extconf.rb понимает следующие опции:
--with-mysql-include=dir
Каталог заголовков MySQL. По умолчанию это /usr/local/include. --with-mysql-lib=dir
Каталог библиотек MySQL. По умолчанию это /usr/local/lib. --with-mysql-dir=dir
Аналогично заданию параметров --with-mysql-include=dir/include и --with-mysql-lib=dir/lib
Теперь введите команду: # ruby -I. ./test.rb hostname user passwd
Скрипт test.rb имеет несколько аргументов: имя хоста сервера MySQL, имя пользователя MySQL и его пароль.
Теперь введите команду: # make install
Если Вы получили ошибку, например, libmysqlclient not found, при тестировании, следует в явном виде задать каталог библиотек в вызове make: # env LD_RUN_PATH=каталог_с_libmysqlclient.so # make
Если используется статическая библиотека libmysqlclient.a, понадобятся некоторые дополнительные библиотеки. Подправьте скрипт extconf.rb и включите в нем "have_library('m')" и "have_library('z')".
Библиотека-оболочка mysql для C++
Автор: Roland Haenel (rh@ginster.net). Эта программа является public domain. Распространять и использовать ее можно совершенно свободно.
Это маленькая оболочка для C++, которая написана вокруг базисной клиентской библиотеки mysql. Целью было создание единого универсального интерфейса для следующих баз данных:
mysql (разработан Michael Widenius). msql (разработан David Hughes). postgres95 (разработан Postgres Group).
Но потому, что mysql намного лучше прочих, контекст этой реализации немного изменился. Теперь стало нужно обеспечить удобный в работе и безопасный интерфейс доступа к mysql.
Программа примера может быть найдена в example.cc. Некоторые слова относительно классов библиотеки:
Класс Database обеспечивает интерфейс связи с базой данных mysqld. Следующие методы выполнены:
int Database::init()
Фактически это не делает ничего в настоящее время, но вызовите его перед выполнением чего-нибудь еще. Это может быть важно для будущих выпусков. int Database::status();
Может быть вызван в любое время. Возвращает состояние подключения: DB_CONNECTION_NONE, DB_CONNECTION_OK или DB_CONNECTION_BAD. char Database::*errorMessage();
Если произошла ошибка, возвращает текст, описывающий ошибку int Database::connect(char *host, char *port, char *db);
Соединяется с базой данных db на машине host. Обратите внимание, что параметр port в настоящее время еще не задействован. void Database::disconnect();
Закрывает текущее подключение. int Database::reset();
Пока не реализовано. DBResult *Database::exec(char *sqlFormat, ...);
void Database::exec(DBResult *res, char *sqlFormat, ...);
Выполнить произвольную команду SQL. Первая форма возвращает экземпляр класса DBResult (даже если имелся сбой). Последняя форма повторно использует уже созданный экземпляр класса DBResult. int DBResult::status();
Возвращает состояние транзакции, связанное с экземпляром класса. Значения могут быть следующими: #define DB_COMMAND_OK 0 // OK: команда выполнена #define DB_EMPTY_QUERY 1 // Запрос не вернул данных #define DB_TUPLES_OK 2 // Запрос вернул данные #define DB_ERROR 5 // Ошибка в команде #define DB_BAD_RESPONSE 6 // Неправильный ответ сервера #define DB_UNEXPECTED 7 // Непонятная ошибка
int DBResult::nrTuples();
Возвращает число выбранных записей (если status() == DB_TUPLES_OK). int DBResult::nrFields();
Возвращает число полей в записи (если status() == DB_TUPLES_OK). char *DBResult::fieldName(int n);
Возвращает имя поля n. int DBResult::fieldSize(int n);
Возвращает размер в байтах поля с номером n. int DBResult::fieldSize(char *name);
Возвращает размер в байтах поля с именем name. void DBResult::seekTuple(int tuple);
Устанавливает внутренний курсор на запись tuple. Она будет возвращена следующим вызовом getTuple(). char **DBResult::getTuple();
Возвращает одну запись. Вызов getTuple()[0] вернет значение первого поля и т.д. char **DBResult::getTuple(int tuple);
Прямой доступ к записи. Для последовательного доступа, пожалуйста, не используйте этот метод. Применяйте вместо него сочетание seekTuple()/getTuple().
Хитрости в реализации
Привилегированные объектные типы для объектов даты/времени определены в пакете mxDateTime ( http://starship.python.net/~lemburg/mxDateTime.html). Это обеспечивает все необходимые конструкторы и методы на уровнях Python и C. Привилегированный объектный тип для объектов Binary является буферным типом, доступный в стандартном Python, начиная с версии 1.5.2. Подробности ищите в документации на Python и в дистрибутиве его исходников (файлы Include/bufferobject.h и Objects/bufferobject.c). Имеется типовая реализация конструкторов для даты/времени, делегирующая работу универсальным конструкторам на основе Unix-импульсов сигнала времени: import time
def DateFromTicks(ticks): return apply(Date,time.localtime(ticks)[:3])
def TimeFromTicks(ticks): return apply(Time,time.localtime(ticks)[3:6])
def TimestampFromTicks(ticks): return apply(Timestamp,time.localtime(ticks)[:6])
Этот класс Python позволяет выполнять вышеупомянутые объекты типа даже при том, что поле кода типа описания выдает много значений для type object: class DBAPITypeObject: def __init__(self,*values): self.values = values def __cmp__(self,other): if other in self.values: return 0 if other < self.values: return 1 else: return -1 Возникающий в результате объект сравнивается со всеми значениями, переданными конструктору. Имеется отрывок кода на Python, который реализует иерархию исключительных ситуаций, определенную выше: import exceptions
class Error(exceptions.StandardError): pass
class Warning(exceptions.StandardError): pass
class InterfaceError(Error): pass
class DatabaseError(Error): pass
class InternalError(DatabaseError): pass
class OperationalError(DatabaseError): pass
class ProgrammingError(DatabaseError): pass
class IntegrityError(DatabaseError): pass
class DataError(DatabaseError): pass
class NotSupportedError(DatabaseError): pass На C Вы можете использовать API PyErr_NewException(fullname,base,NULL), чтобы создать объекты исключительной ситуации.
Интерфейс модулей
Доступ к базе данных сделан доступным через объекты подключения. Модуль должен обеспечивать конструктор для них:
connect(parameters...) Конструктор для создания подключения с базой данных. Возвращает объект подключения. Требуется ряд параметров, которые являются зависимыми от базы данных.
Эти глобальные переменные модуля должны быть определены:
apilevel Строковая константа, устанавливающая поддержанный уровень DB API. В настоящее время допустимы только строки '1.0' и '2.0'. Если не задана, предполагается уровень интерфейса Database API 1.0. threadsafety Целочисленная константа, устанавливающая уровень безопасности потоков, который интерфейс поддерживает. Возможные значения:
0 | Потоки не могут совместно использовать модуль. |
1 | Потоки могут совместно использовать модуль, но не подключения. |
2 | Потоки могут совместно использовать модуль и подключения. |
3 | Потоки могут совместно использовать модуль, курсоры и подключения. |
Совместное использование в вышеупомянутом контексте означает, что два потока могут использовать ресурс без того, чтобы применять mutex-семафор, чтобы выполнить блокировку ресурса. Обратите внимание, что Вы не можете всегда делать внешние ресурсы поточно-безопасными управляя доступом, использующим mutex: ресурс может полагаться на глобальные переменные или другие внешние источники данных, которые находятся вне Вашего управления!
paramstyle Строковая константа. Устанавливает тип маркера параметра, форматирующего ожидаемый интерфейсом. Возможные значения:
'qmark' | Стиль метки запроса, например, '...WHERE name=?' |
'numeric' | Числовой, позиционный стиль, например, '...WHERE name=:1' |
'named' | Именованный стиль, например, '...WHERE name=:name' |
'format' | Формат кодов ANSI C printf, например, '...WHERE name=%s' |
'pyformat' | Расширенные форматные коды языка Python, например, '...WHERE name=%(name)s' |
Модуль должен делать всю информацию об ошибках доступной через эти исключительные ситуации или через подклассы от них:
Warning Исключительная ситуация для важных предупреждений подобно усечениям данных при вставке и т. д. Это должно быть подклассом от Python StandardError. Error Исключительная ситуация, которая является основным классом для всех других исключительных ситуаций ошибки. Вы можете использовать это, чтобы захватить все ошибки с одиночной частью 'except'. Предупреждения не считаются ошибками и таким образом не должны использовать этот класс как ядро. Это обязательно должно быть подклассом Python StandardError. InterfaceError Исключительная ситуация для ошибок, которые связаны с интерфейсом базы данных, а не с самой базой данных. Это должно быть подклассом Error. DatabaseError Исключительная ситуация для ошибок, которые связаны с самой базой данных. Это должно быть подклассом Error. DataError Исключительная ситуация для ошибок, которые появляются из-за проблем с обработанными данными, подобно делению на ноль, числовое значение вне диапазона и т.д. Это должно быть подклассом DatabaseError. OperationalError Исключительная ситуация для ошибок, которые связаны с работой с базой данных и не обязательно подконтрольны программисту, например, непредвиденное разъединение, имя источника данных не найдено, транзакция не могла быть обработана, ошибка распределения памяти произошла в течение обработки и т.д. Это должно быть подклассом от DatabaseError. IntegrityError Исключительная ситуация вызывается, когда воздействуют на реляционную целостность базы данных, например, произошла ошибка проверки внешних ключей. Это должно быть подклассом от DatabaseError. InternalError Исключительная ситуация для случаев, когда база данных сталкивается с внутренней ошибкой, например, курсор больше не имеет силу, транзакция вышла из синхронизации, либо случилось что-то в этом роде. Это должно быть подклассом от DatabaseError. ProgrammingError Исключительная ситуация для ошибок программирования, например, таблица не найдена или уже существует, ошибка синтаксиса в инструкции SQL, неправильное число определенных параметров и т.д. Это должно быть подклассом DatabaseError.
NotSupportedError Исключительная ситуация для ситуации, когда использовался метод или API базы данных, который не поддержан базой данных, например, запрашивается rollback() на подключении, которое не поддерживает транзакции или имеет выключенные транзакции. Это должно быть подклассом DatabaseError.
Если база данных не поддерживает функциональные возможности, требуемые методом, интерфейс должен породить исключительную ситуацию в случае, если метод используется.
Можно также не реализовывать метод вообще, тогда Python сам сгенерирует исключительную ситуацию AttributeError в случае, если метод запрошен. Это позволяет программисту проверять возможности базы данных, используя функцию hasattr().
Это размещение наследования исключительной ситуации: StandardError |__Warning |__Error |__InterfaceError |__DatabaseError |__DataError |__OperationalError |__IntegrityError |__InternalError |__ProgrammingError |__NotSupportedError
Обратите внимание: значения этих исключительных ситуаций не определены. Они должны дать пользователю информацию о том, что пошло не так.
представляет несколько важных нововведений
Python Database API 2. 0 представляет несколько важных нововведений по сравнению с версией 1.0. Некоторые из этих изменений делают невозможным применять старые скрипты с новой версией DB API.
Потребность в отдельном dbi модуле была ликвидирована, и функциональные возможности, объединены непосредственно в интерфейс модуля. Новые конструкторы и Type Objects были добавлены для значений даты/времени, RAW Type Object переименован в BINARY. Возникающий в результате набор должен покрыть все базисные типы данных, обычно присутствующие в современных базах данных на SQL. Были добавлены новые константы (apilevel, threadlevel, paramstyle) и методы (executemany, nextset), чтобы обеспечить лучшее взаимодействие с разными базами данных. Семантика метода callproc(), нужная чтобы вызывать хранимые процедуры, теперь ясно определена. Определение значения возврата execute() изменилось. Раньше значение возврата было основано на типе инструкции SQL (что было не так-то просто реализовать), теперь же оно неопределенно, используйте более гибкий атрибут rowcount вместо этого. Модули могут использовать старый стиль значений возврата, но они больше не переданы под мандат спецификацией и должны рассматриваться как зависимый интерфейс базы данных. Классы основных исключительных ситуаций были включены в спецификацию. Можно расширить иерархию исключительных ситуаций, определенную в этой спецификации, подклассифицируя определенные классы исключительных ситуаций.
Известные проблемы
Хотя спецификация версии 2.0 разъясняет много вопросов, которые были оставлены открытыми в версии 1.0, некоторые все еще остаются проблемами:
Определение полезного значения возврата для nextset() для случая, когда новый набор результат доступен. Создание числового типа с фиксированной точкой для использования в качестве типа для пересчета чисел с минимальными потерями.
Объекты курсоров
Эти объекты представляют курсор базы данных, который используется, чтобы управлять контекстом операции выборки.
Объекты курсоров должны отвечать на следующие методы и атрибуты:
description Этот атрибут только для чтения: последовательность последовательностей с 7 элементами. Каждая из этих последовательностей содержит информацию, описывающую один столбец результата: (name, type_code, display_size, internal_size, precision, scale, null_ok). Этот атрибут будет None для операций, которые не возвращают строки, или если курсор не имел операции, вызываемой через метод executeXXX().
Код type_code может интерпретироваться, сравнивая его с Type Objects, определенными в разделе ниже.
rowcount Этот атрибут только для чтения определяет число строк, обработанных последним вызовом executeXXX() (для SQL-инструкций, вроде select) или затронутых запросом (для SQL-инструкций, подобных update или insert). Атрибут равен -1 в случае, если никакой executeXXX() не выполнился на курсоре. callproc(procname[,parameters]) Этот метод факультативный: все базы данных обеспечивают хранимые процедуры. Вызывает хранимую процедуру базы данных с данным именем. Последовательность параметров должна содержать одну запись для каждого параметра, который процедура ожидает. Результат обращения будет возвращен как изменяемая копия входной последовательности. Входные параметры оставлены нетронутыми, выводимые и вводимо-выводимые параметры будут заменены на возможно новые значения. Процедура может также обеспечивать набор результатов как вывод. Это затем должно быть сделано доступным через стандартные методы fetchXXX(). close() Закрывает курсор немедленно и делает его непригодным, начиная с текущего момента. При попытке что-либо с ним сделать еще, будет вызвана исключительная ситуация Error (или ее подкласс). execute(operation[,parameters]) Препарирует и выполняет операцию базы данных (запрос или команду). Параметры можно обеспечивать как последовательность или отображение. Переменные определены в специфической для базы данных записи. Значения возврата не определены.
Ссылка на операцию будет сохраняться курсором. Если тот же самый объект операции передан снова, то курсор может оптимизировать поведение. Это наиболее эффективно для алгоритмов, где много раз используется та же самая операция, но с разными параметрами. Для достижения максимальной эффективности при многократном использовании операции, самое лучшее использовать метод setinputsizes(), чтобы определить типы параметра и размеры. Для параметра допустимо не соответствовать предопределенной информации: реализация должна это скомпенсировать, возможно, с потерей эффективности.
Параметры могут быть также определены как список, чтобы, например, вставить много строк в одной операции, но этот вид использования не рекомендуется: лучше пользуйтесь executemany().
executemany(operation,seq_of_parameters) Готовит операцию базы данных (запрос или команду), а затем выполняет это для всех последовательностей параметров или отображений, найденных в последовательности seq_of_parameters.
Модули могут выполнить этот метод, используя многократные обращения к методу execute() или используя операции массива, чтобы база данных обработала всю последовательность в целом в одном обращении.
Те же самые комментарии, что касаются execute(), также применяются к этому методу. Значения возврата не определены.
fetchone() Выбирает следующую строку набора результатов запросов, возвращая одиночную последовательность или None, когда больше нет доступных данных. Исключительная ситуация Error (или ее подкласс) произойдет, если предыдущее обращение к executeXXX() не производило никакого набора результатов. fetchmany([size=cursor.arraysize]) Выбирает следующую строку набора результатов запросов, возвращая последовательность последовательностей (например, список tuples). Пустая последовательность будет возвращена, когда больше нет доступных строк. Число строк, которое надо выбрать за обращение, определено параметром. Если это не задано, arraysize курсора определяет число строк, которые будут выбраны. Метод должен пробовать выбирать так много строк, как уаазано параметром. Если это невозможно из-за определенного числа строк, меньшее количество строк может быть возвращено.
Исключительная ситуация Error ( или ее подкласс) произойдет, если предыдущее обращение к executeXXX() не производило никакого набора результатов.
Обратите внимание, что имеются сложности с эффективностью, включаемые с параметром размера. Для достижения оптимальной эффективности, обычно самое лучшее использовать arraysize.
fetchall() Выбирает все оставшиеся строки результата запроса, возвращая их как последовательность последовательностей (например, список tuples). Обратите внимание, что атрибут arraysize курсора может воздействовать на эффективность этой операции. Исключительная ситуация Error (или ее подкласс) произойдет, если предыдущее обращение к executeXXX() не производило никакого набора результатов. nextset() Этот метод факультативный, поскольку не все базы данных поддерживают многократные наборы результатов.
Этот метод будет переводить курсор к следующему доступному набору, отбрасывая любые остающиеся строки из текущего (актуального) набора.
Если не имеется больше никаких наборов, метод возвращает None. Иначе он возвращает значение true, и последующие обращения к методам выборки возвратят строки из следующего набора результатов.
Исключительная ситуация Error (или ее подкласс) произойдет, если предыдущее обращение к executeXXX() не производило никакого набора результатов.
Обратите внимание, что интерфейс может выполнять выборку строки, используя массивы и другие оптимизацию. Не гарантируется, что обращение к этому методу только переместит связанный курсор вперед.
arraysize Этот атрибут для чтения-записи определяет число строк, которое надо выбрать с помощью fetchmany() за раз. Значение по умолчанию 1 (выбрать одиночную строку результатов)
Реализации должны отслеживать это значение применительно к методу fetchmany(), но никто не запрещает реально работать с базой данных каким-либо иным способом. Это может также использоваться в реализации метода executemany().
setinputsizes(sizes) Это может использоваться перед обращением для executeXXX() к предопределенным областям памяти для параметров операции. sizes определен как последовательность: один элемент для каждого входного параметра. Элемент должен быть Type Object, который соответствует вводу, который будет использоваться, или это должно быть целым числом, определяющим максимальную длину параметра строки. Если элемент равен None, то никакая предопределенная область памяти не будет зарезервирована для этого столбца (это полезно, чтобы избегать предопределенных областей для больших вводов). Метод не является обязательным для использования и реализации. setoutputsize(size[,column]) Устанавливает размер буфера столбца для выборок больших столбцов (например, LONG, BLOB и им подобных). Столбец определен как индекс в последовательности результатов. Отсутствие определения column установит заданный по умолчанию размер для всех больших столбцов в курсоре. Метод не является обязательным для использования и реализации.
Объекты подключения
Объекты подключения должны отвечать на следующие методы:
close() Закрыть подключение немедленно. Подключение будет непригодным, начиная с этого момента. Если с ним попытаться что-то сделать, будет вызвана исключительная ситуация Error (или подкласс от нее). То же самое применяется ко всем объектам курсора, пробующим использовать подключение. commit() Передать любую ждущую обработки транзакцию на базу данных. Обратите внимание, что если база данных поддерживает auto-commit, это свойство надо заранее выключить. Метод интерфейса можно обеспечивать, чтобы иметь возможность отмены изменений.
Модули баз данных, которые не поддерживают транзакции, должны выполнить этот метод с не имеющими силу функциональными возможностями.
rollback() Этот метод факультативный, поскольку не все базы данных обеспечивают поддержку транзакции. В случае если база данных обеспечивает транзакции, этот метод заставляет базу данных откатиться обратно к началу любой ждущей обработки транзакции. Закрытие подключения без того, чтобы завершить транзакцию, сначала заставит выполниться неявную обратную перемотку. cursor() Возвращает новый объект курсора, использующий подключения. Если база данных не обеспечивает прямое понятие (концепцию) курсора, модуль должен будет подражать курсорам, используя другие средства для соответствия спецификации.
Параметры конструктора подключения должны быть выполнены как параметры ключевого слова для более интуитивного использования и следовать этому порядку параметров:
dsn | Источник данных как строка | обязательно |
user | Имя пользователя как строка | опционально |
password | Пароль пользователя как строка | опционально |
host | Имя хоста | опционально |
database | Имя базы данных | опционально |
Например, конструктор подключения мог бы выглядеть следующим образом: connect(dsn='myhost:MYDB',user='guido',password='234+$').
Этот API был определен, чтобы
Этот API был определен, чтобы привести к одному знаменателю модули Python, которые используются, чтобы обратиться к базам данных. Этот документ описывает Python Database API 2.0. Спецификация интерфейса состоит из нескольких разделов:
Интерфейс модулей Объекты подключения Объекты курсоров Хитрости в реализации Изменения при переходе с версии 1.0 на 2.0
Комментарии и вопросы относительно этой спецификации могут быть направлены на .
Для получения большего количества информации относительно связи с помощью интерфейса базы данных с Python и о доступных пакетах изучите руководство на http://www.python.org/topics/database.
Типы конструкторов и объектов
Многие базы данных должны иметь ввод в специфическом формате для связывания с входными параметрами операции. Например, если ввод предназначен для столбца DATE, то это будет связано с базой данных в специфическом формате строки. Подобные проблемы существуют для столбцов "Row ID" или больших двоичных элементов (например, столбцов blob или RAW). Это представляет проблемы для Python, начиная с параметров для метода без контроля типов executeXXX(). Когда модуль базы данных видит строковый объект, он не знает сходу, как с ним быть.
Чтобы преодолеть эту проблему, модуль должен обеспечить конструкторы, определенные ниже, чтобы создать объекты, которые могут хранить специальные значения. При передаче к методам курсора, модуль может затем обнаружить соответствующий тип входного параметра и обработать его соответственно.
Атрибут description объекта курсора возвращает информацию относительно каждого из столбцов результата запроса. Здесь type_code должен быть равен одному из Type Objects, определенных ниже. Эти самые Type Objects могут быть равны больше, чем одному коду типа (например, DATETIME может быть равен кодам типа для столбцов даты, времени и метки времени).
Модуль экспортирует следующие конструкторы:
Date(year,month,day) Эта функция создает объект, хранящий значение даты. Time(hour,minute,second) Эта функция создает объект, хранящий значение времени. Timestamp(year,month,day,hour,minute,second) Эта функция создает объект, хранящий значение метки времени. DateFromTicks(ticks) Эта функция создает объект, хранящий значение даты с данного значения импульсов сигнала времени (число секунд, начиная с epoch, согласно стандартному модулю Python time). TimeFromTicks(ticks) Эта функция создает объект, хранящий значение времени с данного значения импульсов сигнала времени (число секунд, начиная с epoch, согласно стандартному модулю Python time). TimestampFromTicks(ticks) Эта функция создает объект, хранящий значение метки времени с данного значения импульсов сигнала времени (число секунд, начиная с epoch, согласно стандартному модулю Python time). Binary(string) Эта функция создает объект, способный хранить строковое двоичное значение типа long. STRING Этот объект используется, чтобы описать столбцы в базе данных, которые являются основанными на строках (например, типа CHAR). BINARY Этот объект используется, чтобы описать двоичные (long) столбцы в базе данных (например, LONG, RAW, BLOB). NUMBER Этот объект используется, чтобы описать числовые столбцы в базе данных. DATETIME Этот объект используется, чтобы описать столбцы даты/времени в базе данных. ROWID Этот объект используется, чтобы описать "Row ID" столбец в базе данных.
SQL-значение NULL представляется на вводе и выводе как Python None.
Обратите внимание: использование Unix-импульсов сигнала времени для связи с помощью интерфейса базы данных может вызвать проблемы из-за ограниченного диапазона даты, который они покрывают.
Интерфейс базы данных может поддерживать
Интерфейс базы данных может поддерживать именованные курсоры, позволяя задавать методу параметр-строку. Это свойство пока не является частью спецификации, так как оно сильно усложняет семантику методов fetchXXX().
Модуль использует метод __getitem__ объекта параметров, чтобы отобразить позиции (целые числа) или имена (строки) к значениям параметра. Это учитывает последовательности и отображения, которые нужно использовать как ввод.
Значение передается базе данных напрямую. В практических условиях это означает, что входное значение непосредственно используется как значение в операции. Пользователь не должен требоваться, чтобы экранировать значение так, чтобы оно могло использоваться: значение должно быть равно фактическому параметру для базы данных.
Атрибут rowcount может быть реализован так, что модифицирует значение динамически. Это может быть полезно для баз данных, которые возвращают используемые значения rowcount только после первого обращения к методу fetchXXX().
Доступ к данным
К данным в текущей строке в наборе результатов можно обращаться, вызывая GetField или GetFieldN. GetField вызывается с именем поля как параметр и возвращает символьный указатель на данные или символьный указатель на EOF в случае сбоя. GetFieldN работает подобным способом, за исключением того, что GetFieldN вызывается с номером желательного поля (отсчет начинается с 0).
Файлы заголовков
В настоящее время все подпрограммы MyC включены в один файл заголовков database.h. Имя этого файла не критическое и может быть изменено в любое время, чтобы удовлетворить потребности специфического проекта.
Этот файл должен быть включен первым, также нужно включить stdio.h и stdlib.h. Если директива #define MYC_DEBUG помещена перед включением database.h, то обширный код отладки будет записан в поток stderr.
Инициализация
При вызове OpenDatabase() с именем базы данных, которая будет открыта, именем хоста, именем пользователя и паролем функция инициализирует прикладную программу и открывает выбранную базу данных. EOF возвращен при сбое, NULL возвращен при успехе.
Вызов OpenRecordset() со строкой представляющей собой корректный запрос SQL, открывает набор результатов, который содержит результаты запроса. OpenRecordset() возвращает EOF при ошибке и NULL при успехе. Число записей в наборе результатов может быть получено вызовом RecordCount(), который возвращает число записей в наборе результатов как целое число без знака.
Компиляция
Программы MyC компилируются аналогично любым другим программам, использующим MySQL C API.
Ограничения
MyC не предназначен, чтобы открывать больше, чем один набор результатов за раз. Поддержка нескольких наборов результатов будет в следующем выпуске.
Если набор результатов не имеет уникального ключа, связанного с каждой записью, то Delete() удалит только первое соответствие названной записи. Это отличие от модели DAO, в которой удаляется только в настоящий момент указанная запись, неважно первая она или нет.
Сейчас MyC работает только под Linux, но планируется перенос на другие версии UNIX. Попыток переноса на платформу Windows не было.
Никаких тестов на утечки памяти пока не проводилось для MyC.
Пожалуйста не забудьте, что этот код ALPHA, так что он постоянно будет меняться. В коде почти наверняка есть ошибки, так что будьте осторожны с применением его в ответственных участках своих программ. У автора все работает должным образом, должно бы и у Вас работать, но никаких гарантий пока дать не могу.
Перемещение внутри набора результатов
Набор результатов может быть пройден и изучен с помощью вызовов MoveNext, MovePrev, MoveFirst и MoveLast, которые перемещают в следующий, предыдущий, первый и в последний результат в наборе результатов соответственно. Если набор результатов некорректен, эти подпрограммы возвращают значение EOF, иначе они возвращают NULL.
Получение информации
В настоящее время поддерживаются следующие информационные подпрограммы, RecordCount(), FieldCount(), AbsolutePosition() и RecordsetEOF(). RecordCount возвращает целое число без знака, указывающее текущее число записей в наборе результатов. FieldCount возвращает число полей в строке набора результатов. FieldValue вызывается с номером поля и возвращает его значение, в то время как FieldName тоже вызывается с номером поля, но возвращает уже его имя. AbsolutePosition возвращает номер строки текущей строки в наборе результатов. RecordsetEOF возвращает TRUE, если не имеется никаких имеющих силу записей в наборе результатов, или если текущая строка в конце или начале набора результатов, и никаких имеющих силу записей не осталось, чтобы прочитать их из набора записей. MoveLast и MoveFirst устанавливают RecordsetEOF в TRUE.
Разработчик пакета
Автор этого пакета: Ed Carp. Связаться с ним можно по erc@pobox.com. Есть и веб-страница www.pobox.com/~erc. Он технический администратор и коммерческий программный разработчик, с обширным опытом в управлении проектами от начала до конца, а также в разработке программ на C и VB.
Удаление данных
Вызов Delete() с именем таблицы удалит текущую строку из таблицы. Если имеются строки с двойными данными, только первая строка будет удалена.
Все и сразу
Прикладные программы очень просто писать с MyC. В следующих примерах существует таблица test в базе данных mysql, а в ней есть 5 записей заданных следующим образом:
+--------+-----+ | name | num | +--------+-----+ | item 0 | 0 | | item 1 | 1 | | item 2 | 2 | | item 3 | 3 | | item 4 | 4 | +--------+-----+
Предположим, например, что прикладная программа должна сделать запрос к базе данных и записать все данные в поток stdout:
#include "database.h" main () { int i;
OpenDatabase("mysql", NULL, NULL, NULL); OpenRecordset("select * from test"); while(RecordsetEOF () != EOF) { for (i = 0; i < FieldCount(); i++) printf("%s\t", GetFieldN(i)); puts(""); MoveNext(); } CloseRecordset(); CloseDatabase(); exit(0); }
Немного более сложный пример иллюстрирует добавление, изменение и удаление данных. Этот пример будет формировать таблицу test, вносить в список все данные в таблице, затем просматривать таблицу, заменяя item 3 на item 5 и попутно удаляя item 4:
#include "database.h" main () { int i; char buf[10], buf2[5];
OpenDatabase("mysql", NULL, NULL, NULL); OpenRecordset("delete from test"); CloseRecordset(); OpenRecordset("select * from test"); for (i = 0; i < 5; i++) { AddNew(); sprintf(buf, "item %d", i); sprintf(buf2, "%d", i); SetField("name", buf); SetField("num", buf2); Update("test"); } Refresh(); MoveFirst(); while (RecordsetEOF () != EOF) { for (i = 0; i < FieldCount (); i++) printf("%s\t", GetFieldN(i)); puts(""); MoveNext(); } MoveFirst (); while (RecordsetEOF () != EOF) { printf ("Looking at '%s'\n", GetField ("name")); if (strcmp(GetField("name"), "item 3") == 0) { puts("Changing data"); Edit(); SetField("name", "item 5"); Update("test"); } if (strcmp(GetField("name"), "item 4") == 0) { puts("Deleting data"); Delete("test"); } MoveNext(); } CloseRecordset(); CloseDatabase(); exit(0); }
MyC представляет собой набор простых
MyC представляет собой набор простых подпрограмм C, предназначенных, чтобы сделать создание прикладных программ для использования с базой данных MySQL проще, особенно для тех, кто знаком с Microsoft DAO engine model (используемой в пакетах Microsoft Access и Microsoft Visual Basic).
MyC использует подобную модель, чтобы обратиться к данным внутри базы данных: OpenDatabase, чтобы открыть базу данных, OpenRecordset, чтобы открыть набор результатов, Move, чтобы двигаться внутри набора результатов, AddNew/Edit и Update/Delete, чтобы добавлять, редактировать или удалять данные внутри базы данных.
Запись данных
Данные могут быть записаны в таблицу одним из двух путей: вызовом OpenRecordset() с запросом INSERT INTO или UPDATE (или любой другой имеющей силу в этом отношении инструкцией SQL), или использованием встроенных функций AddNew или Edit.
AddNew() вызывается без параметров и устанавливает внутренние флажки так, что последующее обращение к Update() генерирует инструкцию SQL INSERT INTO. Точно так же Edit() вызывается без параметров и устанавливает внутренние флажки так, что последующее обращение к функции Update() сгенерирует инструкцию SQL UPDATE.
Чтобы устанавливать индивидуальные поля используются SetField, SetFieldN или SetFieldB. SetField вызывается с двумя параметрами: именем поля, которое будет установлено, и значением для него. Точно так же вызывается и SetFieldN, но первый параметр задает номер поля, а не его имя. SetFieldB используется с двоичными данными, и преобразует двоичные данные и NULL в форму, которая может быть сохранена. Обратите внимание, что SetFieldB перезаписывает указанные строки. Никакого средства пока не сделано для преобразования чистых двоичных данных, хотя можно вызывать mysql_escape_string() и передавать возвращенный указатель функциям SetField или SetFieldN.
Важно обратить внимание, что SetField и подобные подпрограммы сохраняют только указатель на данные, которые будут записаны, а не сами данные.
В конце концов поля установлены, Update() вызван с именем таблицы, которую нужно модифицировать. Update() вернет EOF при ошибке или NULL при успехе.
После того, как данные добавлены или модифицированы в таблице, иногда полезно иметь текущий (актуальный) набор записей, отражающий измененные данные. Вызов Refresh() заново выполнит запрос, выполненный последним OpenRecordset() (до 4096 байт) и эквивалентен вызову OpenRecordset(), за исключением того, что текущая строка та же, что и перед вызовом Refresh().
MyDAO: библиотека-оболочка для C++
Версия v0.1 (19-Feb-2000). Автор: Satish (spitfire@pn3.vsnl.net.in). Лицензия: Feel free to use/copy/modify/add bugs/find bugs, but keep the author informed.
Руководство программиста
dbconnect class: Один объект подключения должен быть создан. Это ответственно за соединение с сервером MySQL и открытие базы данных. Свойства:
bool Connected;
Connected равно true, если подключение к серверу MySQL работает. MYSQL *DBase;
DBase является указателем на структуру MYSQL. Это требуется, чтобы открыть набор результатов.
Методы:
void dbconnect::Connect(char *host, char *port, char *uname, char*pwd);
Пытается соединиться с сервером MySQL, используя указанные параметры хоста, порта, имени пользователя и пароля. Если подключение успешно установлено, свойство Connected будет true. void dbconnect::Disconnect();
Разъединяет текущее подключение с сервером MySQL. bool dbconnect::OpenDB(char *db);
Открывает базу данных db. Если все в порядке, вернет true.
Пример: dbconnect MyConnect; char host[]="localhost"; char port[]="3306"; char name[]="satish"; char pwd[]=""; char db[]="orders";
MyConnect.Connect(host, port, name, pwd); if (MyConnect.Connected) cout << "Connected" << endl; else { cout << "Connection failed" << endl; return; } if (!MyConnect.OpenDB(db)) { cout << "Can not open selected database" << endl; return; } else { cout << "Opened datbase: " << db << endl; // open recorset(s)... // Manipulate data... } MyConnect.Disconnect();
recordset class: Любое количество наборов результатов может быть создано из этого класса. Он имеет много свойств для простого манипулирования данными.
Свойства:
char RecSource[MAX_RECSRC_LEN];
Источник записей, из которых данные должны обрабатываться. Это должна быть SQL-инструкция SELECT, возвращающая записи. unsigned long int RecordCount;
Число строк в открытом наборе результатов. unsigned long int AffectedRows;
Может использоваться только с Update, AddNew или Delete. Число строк фактически обработанных сервером. bool EOR;
Конец набора результатов. True, если Вы двигаетесь в последнюю строку. bool BOR;
Начало набора результатов. True, если Вы двигаетесь первую строку. Замечание: EOR и BOR вместе будут равны true, если RecordCount=0.
Методы:
void recordset::OpenRecordset(MYSQL *Structmysql, char *sql);
Открывает набор результатов основанный на SQL-инструкции select. void recordset::CloseRecordset();
Закрывает набор результатов. Он должен быть закрыт, чтобы освободить память, используемую им. void recordset::MoveNext();
Перемещается в следующую строку набора результатов. Если уже достигнута последняя строка, в ней и останется. void recordset::MovePrevious();
Перемещается в предыдущую строку набора результатов. Если уже достигнута первая строка, в ней и останется. void recordset::MoveFirst();
Перемещается в первую строку набора результатов. void recordset::MoveLast();
Перемещается в последнюю строку набора результатов. char* recordset::GetField(char *FName);
Возвращает содержание поля FName. void recordset::SetField(char *FName, char *Value);
Устанавливает содержание поля FName в значение Value. Изменения будут отброшены, если после установки значения не используется метод Update/AddNew. void recordset::Edit();
Должен использоваться перед методами SetField и Update, иначе все изменения будет отброшены. void recordset::AddNew();
Используется, чтобы добавить новую строку в набор результатов. Для работы этого метода набор результатов должен быть основан на таблице. Метод Update должен использоваться после установки всех значений поля. Определение WHERE не должно использоваться в методе Update, если оно уже используется с методом AddNew. Свойство AffectedRows выдаст число добавленных строк. void rercordset::Update(char *Where);
Используется, чтобы редактировать или добавить строку вместе с методами Edit/AddNew. Определение WHERE не должно использоваться с AddNew. void recordset::Delete(char *Where);
Применяется, чтобы удалить строки из набора результатов. void recordset::Refresh();
Изменения, сделанные методом Update, невидимы, если метод Refresh не используется. Обновите набор результатов немедленно после Update. char* recordset::GetFieldN(int FNum);
Аналогично GetField, но вместо имени поля используется его код (номер). void recordset::SetFieldN(int FNum, char *Value)
Аналогично SetField, но вместо имени поля используется его код (номер).
Пример 1: // Продолжение примера из dbconnect. // Откроем таблицу заказчиков (customers) и распечатаем // все записи из нее. recordset MySet; char sql[]="SELECT * FROM customers";
MySet.OpenRecordset(MyConnect.DBase, sql); if (MySet.EOR && MySet.BOR){ cout << "No records found" << endl; return; } else { // Show number of records cout << "No. of records: " << MySet.RecordCount << endl; // Show all records while (!MySet.EOR) { cout << MySet.GetField("or_id") << "\t"; cout << MySet.GetField("customers") << "\t"; cout << MySet.GetField("city") << endl; MySet.MoveNext(); } }
Пример 2: // Добавление новой строки в таблицу заказчиков. MySet.AddNew(); MySet.SetField("cs_id", "7"); MySet.SetField("name", "Satish"); MySet.SetField("city", "Pune"); MySet.Update(""); // where не используется! MySet.Refresh(); // Сделаем изменения видимыми.
Пример 3: // Изменение имени заказчика. MySet.Edit(); MySet.SetField("cs_id", "7"); MySet.SetField("name", "Suresh"); MySet.SetField("city", "Pune"); MySet.Update("or_id=7"); // where здесь необходимо использовать. MySet.Refresh(); // Сделаем изменения видимыми.
Пример 4: // Удаление записи. MySet.Delete("name='Suresh'"); MySet.Refresh(); // Сделаем изменения видимыми.
Пример 5: // Закроем набор результатов после употребления. Это ОБЯЗАТЕЛЬНО! MySet.CloseRecordset();
Что еще надо сделать:
Лучший контроль ошибок Методы поиска информации (FindFirst, FindNext, FindPrevious, FindLast) Сделать графическое представление набора результатов
библиотека для сервера MySQL. Разработчик
Это C++ библиотека для сервера MySQL. Разработчик данного пакета искал библиотеку C++, которая может создавать и работать с Data Access Objects. Он натолкнулся на программное обеспечение, написанное Roland Hanel (MySQL C++) и Ed Carp (MyC). Но MyC написан на чистом C и не может создавать объект в истинном смысле. Также это не может создавать и работать с несколькими наборами результатов. На основе этих пакетов была написан пакет MyDAO ver 0.1.