MysqIPerl
MysqIPerl
Монти Видениус, автор MySQL, написал также и интерфейс Perl к MySQL, Mysql.pm. Он основывался на модуле Msql.pm для mSQL, поэтому интерфейсы двух модулей почти идентичны. На практике мы недавно преобразовали целый сайт из mSQL в MySQL, выполнив команду «perl -e 's/^Msql/Mysql/>> *.cgi» в каждом каталоге, содержащем CGI. Это составило 95% всей работы. Разумеется, при этом вы не получаете преимуществ MySQL, но таким путем можно быстро и легко встать на путь использования MySQL. Mysql.pm входит составной частью в пакет msql-mysql-modules Йохена Видмана (Jochen Wiedmann).
Одним из самых больших различий между MySQL и mSQL является их работа с последовательностями. В mSQL последовательность определяется в таблице командой CREATE SEQUENCE on tablename . Значение последовательности можно получать после этого, как обычное поле таблицы командой SELECT _se.q from tablename . В MySQL к первичному ключу добавляется флаг AU-TO_INCREMENT . При попытке ввода null в это поле оно автоматически инкрементируется. Как MySQL, так и mSQL допускают в каждой таблице только одну последовательность. Подробное обсуждение последовательностей в MySQL и mSQL см. в главе 6 «Диалект SQL, используемый в MySQL и mSQL».
Чтобы показать некоторые функции Mysql.pm, вернемся к примеру с экзаменами. Разобравшись с subject.cgi, займемся таблицей сведений об учащихся. Ее структура такова:
CREATE TABLE student (
id INT NOT NULL auto_increment,
first VARCHAR(50),
middle VARCHAR(50),
last VARCHAR(50),
ext VARCHAR(50),
subjects VARCHAR(100),
age INT,
sex INT,
address BLOB,
city VARCHAR(50),
state VARCHAR(5),
zip VARCHAR(10),
phone VARCHAR(10),
PRIMARY KEY (id)
)
В этой таблице находятся все данные, используемые программой subject, cgi, a также другие сведения, которые относятся к учащемуся. Программа student.cgi, работающая с этой таблицей, должна выполнять все те функции, которые программа subject.cgi выполняла в отношении таблицы subject.
Нельзя работать с базой данных mSQL через модуль Mysql.pm, как и с базой MySQL через Msql.pm. Программа stu-dent.cgi предполагает, что таблица предметов находится в базе данных MySQL. Аналогично, программа subject.cgi рассчитывает на mSQL-версию таблицы учащихся.
Чтобы продемонстрировать, как работает Mysql.pm, мы подробно изучим ту часть student.cgi, которая позволяет пользователю изменять сведения об учащемся. Так же как операция «add» (добавление) в примере для Msql.pm была разбита на четыре отдельные функции, операция «change» (изменение) разбита здесь на три отдельные функции.
Первая функция - изменения, выводит форму, позволяющую пользователю найти учащегося, данные о котором нужно изменить:
sub change {
print header, start_html('title'=>'Поиск учащегося для изменения денных'
'BGCOLOR'=>'white');
&print_form('search2', Поиск учащегося для изменения данных',1);
print <<END_OF_HTML; <р>
<INPUT TYPE=HIDDEN NAME="subaction" VALUE="change2">
<INPUT TYPE=SUBMIT VALUE=" Искать учащегося ">
<INPUT TYPE=SUBMIT NAME="all" VALUE=" Просмотр всех учащихся ">
<INPUT TYPE=RESET>
</form></body></html>
END_OF_HTML }
Форма, используемая для поиска учащегося с целью изменения, настолько сходна с формами для просмотра данных и для добавления, что во всех трех случаях используется одна функция, print_form , показанная ниже:
sub print_form {
my ($action,$message,$any) = @_;
print <<END_OF_HTML;
<FORM METHOD=post ACTION="students.cgi">
<INPUT TYPE=HIDDEN NAME="action" VALUE="$action">
<H1>$message</h1>
END_OF_HTML
if ($any) {
print <<END_OF_HTML; <р>Поиск
<SELECT NAME="bool">
<OPTION VALUE="ог">любой
<OPTION VALUE="and">Bce </select> выбранные вами.
END_OF_HTML
У
print <<END_OF_HTML; <P>
Имя:
<INPUT NAME="first" SIZE=20>
Отчество:
<INPUT NAME="middle" SIZE=10>
Фамилия:
<INPUT NAME="last" SIZE=20>
МЛ./III/И т.д..:
<INPUT NAME="ext" SIZE=5> <br>
Адрес:
<INPUT NAME="address" SIZE=40><br>
Город:
<INPUT NAME="city" SIZE=20>
Штат:
<INPUT NAME="state" SIZE=5>
Почтовый индекс:
<INPUT NAME="zip" SIZE=10><br>
Телефон:
<INPUT NAME="phone" SIZE=15><br>
Возраст:
<INPUT NAME="age" SIZE=5>
Пол:
<SELECT NAME="sex">
END_OF_HTML
if ($any) {
print <<END_OF_HTML; <OPTION VALUE="">He имеет значения
END_OF_HTML
}
print <<END_OF_HTML;
<OPTION VALUE="1">Myжской
<OPTION VALUE="2">Женский
</select><br>
<P>
Записан на:<br>
END_OF_HTML
&print_subjects("MULTIPLE SIZE=5");
}
Благодаря использованию трех параметров эта функция настраивает шаблон формы так, что может использоваться в самых различных целях. Обратите внимание, что эта вспомогательная функция использует другую вспомогательную функцию, print_subjects . Последняя выводит список всех имеющихся предметов из таблицы subject, как в примере Msql.pm.
sub print_subjects { my $modifier = "";
$modifier = shift if @_;
print qq%<SELECT NAME="subjects" $modifier>\n%;
my $out = $dbh->query("select * from subject order by name");
while(my(%keys)=$out->fetchhash) {
print qq%<OPTION VALUE="$keys{'id'}">$keys{'name'}\n%;
}
print "</select>\n";
}
Параметры поиска, введенные в первую форму, передаются функции search2, фактически осуществляющей поиск. На самом деле это функция, написанная для поиска учащегося, данные о котором нужно показать. Поскольку она делает как раз то, что нам требуется, мы можем ею воспользоваться, если сообщим ей, что после поиска хотим перейти
к следующей функции изменения, change2. Для этого мы ввели в форму скрытую переменную subaction=change2 . Она сообщает search2, куда отправить пользователя дальше:
sub search2 {
my $out = $dbh->query(&make_search_query);
my $hits = $out->numrows;
my $subaction = "view";
$subaction = param('subaction')
if param('subaction');
print header, start_html('title'=>'Результаты поиска учащихся', 'BGCOLOR'=>'white');
if (not Shits) {
print <<END_OF_HTML;
<Н1>Учащихся не найдено</h1>
<P>
He найдено учащихся, удовлетворяющих вашему критерию.
END_OF_HTML } else {
print <<END_OF_HTML;
<H1> Найдено $hits учащихся </h1> <р>
<UL>
END_OF_HTML
while(my(%fields)=$out->fetchhash) {
print qq%<LI>
<A HREF="students.cgi?action=$subaction&id=$fields
{'id'}">$fields{'first'} $fields{'middle'} $fields{'last'}%;
print ", $fields{'ext'}" if $fields{'ext'};
print "\n</a>"; } }
print <<END_OF_HTML; </ul> <p>
<A HREF="students.cgi?action=search">HcKaTb</a> снова.
</body></html>
END_OF_HTML }
С помощью функции make_search_query эта функция сначала ищет учащихся, отвечающих критериям поиска. Затем она выводит список найденных записей, среди которых пользователь может сделать выбор. ID выбранной записи передается функции change2, как показано ниже:
sub change2 {
my $out = $dbh->query
("select * from student where id=$id");
my($did,Ifirst,$middle,$last,
$ext,Ssubjects.Sage,$sex,$address,
$city,$state,$zip,$phone) = $out->fetch row;
my ©subjects = split(/:/,$subjects);
shift,©subjects;
my $name = "$first $tmiddle $last";
if ($ext) { $name .= ", $ext"; }
print header, start_html('title'=>"$name", 'BGCOLOR'=>'white');
print <<END_OF_HTML;
<H1>$name</h1> <p>
<FORM ACTION="students.cgi" METHOD=POST>
<INPUT TYPE=HIDDEN NAME="action" VALUE="change3">
<INPUT TYPE^HIDDEN NAME="id" VALUE="$id">
Имя:
<INPUT NAME="first" VALUE="$first" SIZE=20>
Отчество:
<INPUT NAME="middle" VALUE="$middle" SIZE=10>
Фамилия:
<INPUT NAME="last" VALUE="$last" SIZE=20>
МЛ./III/И т.д.
<INPUT NAME="ext" VALUE="$ext" SIZE=5> <br>
Адрес:
<INPUT NAME="address" VALUE="$address" SIZE=40><br>
Город:
<INPUT NAME="city" VALUE="$city" SIZE=20>
Штат:
<INPUT NAME="state" VALUE="$state" SIZE=5>
Почтовый индекс:
<INPUT NAME="zip" VALUE="$zip" SIZE=10xbr>
Телефон:
<INPUT NAME="phone" VALUE="$phone" SIZE=15><br>
Возраст:
<INPUT NAME="age" VALUE="$age" SIZE=5>
Пол:
END_OF_HTML
my %sexes = ( '1' => 'Мужской',
'2' => 'Женский' );
print popup_menu('name'=>'Пол', 'values'=>["!', '2'], 'default'=>"$sex", ' labels'=>\%sexes);
print <<END_OF_HTML; <p>
Записан на:<br>
END_OF_HTML
my @ids = ();
my %subjects = ();
my $out2 = $dbh->query("select id,name from subject order by name");
while(my($id,$subject)=$out2->fetchrow) { push(@ids,Sid);
$subjects{"$id"} = $subject; }
print scrolling_list('name'=>'subjects', 'values'=>[@ids], 'default'=>[@subjects], 'size'=>5, 'multiple'=>'true', 'labels'=>\%subjects);
print <<END_OF_HTML;
<р>
<INPUT TYPE=SUBMIT VALUE=" Изменить данные об учащемся ">
<INPUT TYPE=SUBMIT NAME="delete" VALUE=" Удалить учащегося ">
<INPUT TYPE=RESET>
</form></body></html>
END_OF_HTML
}
Главная задача этой функции - вывести форму, очень похожую на ту, которую порождает print^from. Однако значениями по умолчанию в этой форме должны быть те, которые соответствуют выбранному учащемуся. В результате пользователь может редактировать одни поля, оставляя другие неизменными.
Несколько функций, предоставляемых модулем CGI.pm, оказываются очень удобными при выводе формы со значениями, установленными по умолчанию, особенно функция CGI: :scrolling_list , выводящая блок HTML <SELECT> с заданными параметрами. Среди прочих, функция принимает параметры values, default и labels, относящиеся к значениям каждого тега <OPTION> , задающие выбираемые по умолчанию пункты и их метки, видимые пользователю.
Эта функция выводит заполненную форму, как если бы это была форма для добавления. Разница в том, что это данные для учащегося, уже имеющегося в базе данных. Функция changes принимает данные и обновляет данные в базе, как показано ниже:
sub changes {
if (param('delete')) { &delete2($id); } else {
my Squery = "update student set "; my @query = ();
foreach ('first', 'middle', 'last', 'ext', 'address', 'city', 'state', 'zip', 'phone') {
if (param($_)) { push(@query,"$_ = ".
$dbh->quote(param($_))); } }
push(@query,"age=".param('age')) if param('age');
push(@query,"sex=".param('sex')) if param('sex');
my $subjects = "':";
$subjects .= join(":",param('subjects'));
$subjects .= ":" unless $subjects eq "':";
$subjects .= "'";
push(@query, "subjects=$subjects");
Squery .= join(", ",@query) . " where id=$id"; $dbh->query($query);
print header, start_html('title'=>'Данные об учащемся изменены',
'BGCOLOR'=>'white'); # Вывести форму с сообщением об успехе
}
}
Обратите внимание, что при выборе кнопки «Delete» на странице изменения функция автоматически передает управление функции удаления. Это одно из главных преимуществ объединения в одной программе нескольких функций. Если вмешательства пользователя не требуется, то можно перескакивать между функциями без посылки пользователю сообщений о перенаправлении.
Оставшаяся часть этой функции довольно проста. Данные об учащемся собираются в запросе UPDATE, который отправляется серверу MySQL. Затем пользователю посылается страница с сообщением об успешном завершении работы.