HTML page
14.10. Выполнение команд SQL с помощью DBI и DBD
Проблема
Вы хотите направить запрос SQL в систему управления базами данных (например, Oracle, Sybase, mSQL или MySQL) и обработать полученные результаты.Решение
Воспользуйтесь модулями DBI (DataBase Interface) и DBD (DataBase Driver) от CPAN:use DBI:
$dbh = Dbl->connect('DBI:driver', 'username', 'auth',
{ PrintError => 1, RaiseError => 1})
or die "connecting: $DBI::errstr";
$dbh->do(SQL)
or die "doing: ", $dbh->errstr;
$sth = dbi->prepare(SQL)
or die "preparing: ", $dbh->errstr;
$sth->execute
or die "executing: ", $sth->errstr;
while (@)row = $sth->fetchrow_array) {
# . . .
} $sth->finish;
$dbh->disconnect;
Комментарий
DBI является посредником между программой и всеми драйверами, предназначенными для работы с конкретными СУБД. Для большинства операций нужен манипулятор базы данных (в приведенном выше примере - $dbh).0n ассоциируется с конкретной базой данных и драйвером при вызове DBI->connect.Первый аргумент DBI->connect представляет собой строку, состоящую из трех полей, разделенных двоеточиями. Он определяет источник данных - СУБД, к которой вы подключаетесь. Первое поле всегда содержит символы DBI, а второе - имя драйвера, который вы собираетесь использовать (Oracle, mysql и т. д.). Оставшаяся часть строки передается модулем DBI запрошенному модулю драйвера (например, DBD::mysql) и идентифицирует базу данных. Второй и третий аргументы выполняют аутентификацию пользователя. Четвертым, необязательным аргументом является ссылка на хэш с определением <>трибутов подключения. Если атрибут PrintError равен true, при каждом неудачном вызове метода DBI будет выдавать предупреждение. Присваивание RaiseError имеет аналогичный смысл, за исключением того, что вместо warn будет использоваться die.
Простые команды SQL (но возвращающие записи данных) могут выполняться методом do манипулятора базы данных. При этом возвращается логическая истина или ложь. Для команд SQL, возвращающих записи данных (например, SELECT), необходимо сначала вызвать метод prepare манипулятора базы данных, чтобы создать манипулятор команды. Далее запрос выполняется методом execute, вызванным для манипулятора команды, а записи извлекаются методами выборки fetchrow_array или fetchrow_hashref (возвращает ссылку на хэш. в котором имя поля ассоциируется со значением).
После завершения работы с базой не забудьте отключиться от нее методом disconnect. Если манипулягор базы данных выходит из области действия без предварительного вызова disconnect, модуль DBI выдает предупреждение. Эта мера предосторожности предназначена для тех СУБД, которые должны возвращать память системе и требуют корректного отключения от сервера. Перед отключением манипулятора базы данных манипуляторы команд должны получить неопределенное значение, выйти из области действия или для них должен быть luii.n^in метод finisri. Если этого не сделать, вы получите предупреждение следующего вида: disconnect(OBI::db-HA8H(Ox9df84)) invalidates 1 active cursor(s) at -e line 1, Модуль DBI содержит 'FAQ(perldocDBI::FAQ) и стандартную документацию (j/ei'ldoc DBF). Также существует документация для драйверов конкретных СУБД (например, perldoc. DBD-.-.inysq!'). Прикладной интерфейс DBI не ограничивается простейшим подмножеством, рассмотренным памп: он предоставляет разнообразные возможности выборки результата и взаимодействия со специфическими средствами конкретных СУБД (например, сохраняемыми процедурами). За информацией обращайтесь к документации по модулю драйж;рн. Программа ил примера 14.7 создае! и заполняет таблицу пользователей в MySQL, после чего выполняет в ней поиск. Она использует атрибут RaiseError к потому обходится без проверки возвращаемого значения для каждого метода-Пример 14.7. dbusers
> Смотри также -------------------------------
Документация по DBI и модулям DBD с CPAN, http://www.hef7netica.com/ technologia/perl/DBI/index.html и http://www.perl/com/CPAN/modules/by-category/ О 7 _Database interfaces/.
14.11. Программа: ggh - поиск в глобальном журнале Netscape
Следующая программа выводит содержимое файла Netscape history, db. При вызове ей может передаваться полный URL или (один) шаблон. Если программа вызывается без аргументов, она выводит все содержимое журнала. Если не задан параметр -database, используется файл-/.netscape/history.db.
В каждой выводимой строке указывается URL и время работы. Время преобразуется в формат localtime параметром -localtime (по умолчанию) или в представление gmtime параметром -gmtime или остается в первоначальном формате (параметр -epoch), что может пригодиться для сортировки по дате.
Шаблон задается единственным аргументом, не содержащим : //. Чтобы вывести данные по одному или нескольким URL, передайте их в качестве аргументов:
v% ggh http://www.perl.com/index.html Вывод сведений о адресах, которые вы помните лишь приблизительно (шаблоном считается единственный аргумент, не содержащий : //):.
% ggh perl Вывод всех адресатов электронной почты:
% ggh mailto:
Для вывода всех посещенных сайтов со списками FAQ используется шаблон Perl с внутренним модификатором /I:
% ggh -regexp '(?i)\bfaq\b'
Если вы не хотите, чтобы внутренняя дата была преобразована в формат local time, используйте параметр -epoch:
% ggh -epoch http://www.perl.com/perl/ Если вы предпочитаете формат gmtime, используйте параметр -gmtime:
% ggh -gmtime http://www.perl.com/perl/
Чтобы просмотреть весь файл, не задавайте значения аргументов (вероятно, данные следует перенаправить в утилиту постраничного вывода):
% ggh | less Чтобы отсортировать выходные данные по дате, укажите флаг -epoch:
% ggh -epoch | sort -rn | less
Для сортировки по времени в формате местного часового пояса используется более сложная командная строка:
% ggh -epoch | sort -rn | perl -ре 's/\d+/localtime $&/e' | less
Сопроводительная документация Netscape утверждает, что в журнале используется формат NDBM. Это не соответствует действительности: на самом деле использован формат Berkeley DB, поэтому вместо NDBM_File (входит в стандартную поставку всех систем, на которых работает Perl) в программе загружается DB_File. Исходный текст программы приведен в примере 14.8. Пример 14.8. ggh
#!/usr/bin/perl -w
# ggh - поиск данных в журнале netscape
$USAGE = "eo_complaint;
usage: $0 [-database dbfilename] [-help]
[-epochtime | -localtime | -gmtime]
[ [-regexp] pattern] | href ... ] EO_COMPLAINT
use Getopt::Long;
($opt_database, $opt_epochtime, $opt_localtime, $opt_gmtime,
$opt_regexp, $opt_help, $pattern,
) = (0) x 7;
usage() unless GetOptions qw{ database=s regexp=s epochtime localtime gmtime help };
if ($opt_help) { print $USAGE; exit; }
usage("only one of localtime, gmtime, and epochtime allowed") if $opt_localtime +
$opt_gmtime + $opt_epochtime > 1;
if ( $opt_regexp ) {
$pattern = $opt_regexp;
} elsif (@ARGV && $ARGV[0] Г m(://)) {
$pattern = shift;
}
uoage("can't mix URLs and enpiiciL раИйгпа1;
if $pattern && @ARGV;
if ($pattern && ! eval {'"="' /$pattern/; 1 } ) {
$@ =~ s/ at \w+ line \d+\.//;
die "$0: bad pattern $@>";
}
require DB_File; DB_File->import();
# Отложить загрузку до выполнения
$1=1; # Для перенаправления данных
$dotdir = $env{home} || $env{logname};
$HISTORY = $opt_database || "$dotdir/.netscape/history.db";
die "no netscape history dbase in $HISTORY: $!" unless -e $HISTORY;
die "can't dbmopen $HISTORY: $!" unless dbmopen %hist_db, $HISTORY, 0666;
# Следующая строка - хак, поскольку программисты С,
# которые работали над этим, путали strlen и strlen+1.
# Так мне сказал jwz :-)
$add_nulls = (ord(substr(each %hist_db, -1)) == 0);
# XXX: Сейчас следовало бы сбросить скалярные ключи, но
# не хочется тратить время на полный перебор, И необходимый для связанных хэшей,
# Лучше закрыть и открыть заново?
$nulled_href = "";
$byte_order = "v"; # На pc не понимают "n" (сетевой порядок)
if (@>ARGV) {
foreach $href (@ARGV) {
$nulled_href = $href . ($add_nulls && "\0");
unless ($binary_time = $hist_db{$nulled_href}) { warn "$0: no history entry for href
$href\n";
next;
} $epoch_secs = unpack($byte_order, $binary_time);
$stardate = $opt_epochtime ? $epoch_secs
: $opt_gmtime ? gmtime $epoch_secs : localtime $epoch_secs;
print "$stardate $href\n";
}
} else {
while ( ($href, $binary_time) = each %hist_db ) {
chop $href if $add_nulls;
# gnat reports some binary times are missing
$binary_time = pack($byte_order, 0) unless $binary_time;
$epoch_secs = unpack($byte_order, $binary_time):
$stardate = $opt_epochtime ? $epoch_secs
: $opt_gmtime ? gmtime $epoch_secs : localtime $epoch_secs;
print "$stardate $href\n" unless $pattern && $href !~ /$pattern/o;
}
}
sub usage {
print STDERR "@_\n" if (o)_
die $USAGE:
}
> Смотри также Рецепт 6.17.