当 Perl 的 DBI 在准备语句时遇到错误时,如何避免程序退出?
Posted
技术标签:
【中文标题】当 Perl 的 DBI 在准备语句时遇到错误时,如何避免程序退出?【英文标题】:How can I avoid the program quitting when Perl's DBI encounters an error preparing a statement? 【发布时间】:2009-05-07 20:20:10 【问题描述】:我正在编写一个脚本,它会遍历一个包含数据库中所有其他表名的表。在解析每一行时,它会通过
检查表是否为空select count(*) cnt from $table_name
架构中不再存在某些表,如果我这样做了
select count(*)
直接进入命令提示符,返回错误:
206: 指定的表(adm_rpt_rec)不在数据库中。
当我从 Perl 内部运行它时,它会将这个附加到开头:
DBD::Informix::db 准备失败:SQL: -
如何避免程序在尝试准备此 SQL 语句时退出?
【问题讨论】:
【参考方案1】:一种选择是在构造 $dbh 时不使用 RaiseError => 1。另一种是将prepare包装在eval块中。
【讨论】:
我的 $sth = eval $dbh->prepare( ... ) ;除非定义了 $sth,否则转到下一个表。【参考方案2】:只需将可能失败的调用放在 eval 块中,如下所示:
for my $table (@tables)
my $count;
eval
($count) = $dbi->selectrow_array("select count(*) from $table");
1; #this is here so the block returns true if it succeeds
or do
warn $@;
next;
print "$table has $count rows\n";
尽管在本例中,由于您使用的是 Informix,因此您有一个更好的选择:系统目录表。 Informix 将此类元数据保存在一组系统目录表中。在这种情况下,您需要 systables:
my $sth = $dbh->prepare("select nrows from systables where tabname = ?");
for my $table (@tables)
$sth->execute($table);
my ($count) = $sth->fetchrow_array;
$sth->finish;
unless (defined $count)
print "$table does not exist\n";
next;
print "$table has $count rows\n";
这比count(*)
靠在桌子上更快更安全。系统目录表的完整文档可以在IBM Informix Guide to SQL 中找到(警告这是一个 PDF)。
【讨论】:
警告,上面的代码还没有经过测试,自 2003 年以来我还没有接触过 Informix,但它应该可以工作。 但不那么可靠 - 如果尚未运行 UPDATE STATISTICS,则计数可能是错误的。此外,SELECT COUNT(*) 很快,尽管必须运行其中的多个并不像选择表单 systables 那样快。【参考方案3】:工作代码 - 假设您有一个“商店”数据库。
#!/bin/perl -w
use strict;
use DBI;
my $dbh = DBI->connect('dbi:Informix:stores','','',
RaiseError=>0,PrintError=>1) or die;
$dbh->do("create temp table tlist(tname varchar(128) not null) with no log");
$dbh->do("insert into tlist values('systables')");
$dbh->do("insert into tlist values('syzygy')");
my $sth = $dbh->prepare("select tname from tlist");
$sth->execute;
while (my($tabname) = $sth->fetchrow_array)
my $sql = "select count(*) cnt from $tabname";
my $st2 = $dbh->prepare($sql);
if ($st2)
$st2->execute;
if (my($num) = $st2->fetchrow_array)
print "$tabname: $num\n";
else
print "$tabname: error - missing?\n";
$sth->finish;
$dbh->disconnect;
print "Done - finished under control.\n";
运行上述代码的输出。
systables: 72
DBD::Informix::db prepare failed: SQL: -206: The specified table (syzygy) is not in the database.
ISAM: -111: ISAM error: no record found. at xx.pl line 14.
Done - finished under control.
这打印了错误 (PrintError=>1
),但继续。把 1 改成 0 就不会出现错误了。 $tabname
和 $num
声明中的括号至关重要 - 数组上下文与标量上下文。
【讨论】:
以上是关于当 Perl 的 DBI 在准备语句时遇到错误时,如何避免程序退出?的主要内容,如果未能解决你的问题,请参考以下文章
当跟踪中的语句返回 1 时,为啥 perl DBI 返回 0 行