为什么DBI的RaiseError总是不会触发我的CORE :: GLOBAL :: die子程序?

时间:2014-01-16 18:55:15

标签: perl dbi

我按照brian d foy' article on the subject中的描述覆盖CORE::GLOBAL::die

BEGIN {
    *CORE::GLOBAL::die = sub {
        say "In CORE::GLOBAL::die: [@_]";
        CORE::die(@_) if $^S;
        exit 1;
    }
}

最终目标是将致命错误写入日志,但现在这已经足够了。让我们创建一个启用了RaiseError的数据库句柄并执行某些操作来触发错误:

use DBI;

# Wrong password
my $dbh = DBI->connect(..., { PrintError => 0, RaiseError => 1 });

输出:

In CORE::GLOBAL::die: [DBI connect(...) failed: Access denied for user ...

到目前为止一切顺利。让我们在其上抛出一些不好的SQL:

use DBI;

my $dbh = DBI->connect(..., { PrintError => 0, RaiseError => 1 });
my $sth = $dbh->prepare('SLECT 1');
$sth->execute;

输出:

DBD::mysql::st execute failed: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SLECT 1' at line 1 at ...

嗯,不是我的预期(没有In CORE::GLOBAL::die消息)。根据{{​​3}},当RaiseError开启时,

  

任何导致错误的方法都会导致DBI有效地执行die("$class $method failed: $DBI::errstr")

我想关键字有效,因为我希望实际调用die来调用我的CORE::GLOBAL::die版本。

我可以通过设置die

将所有错误强制设为HandleError
my $dbh = DBI->connect(..., { HandleError => sub { die shift; } })

但由于RaiseError"可用于强制错误引发异常,而不是简单地以正常方式返回错误代码,"我不明白为什么这是必要的。为什么设置RaiseError始终导致错误调用CORE::GLOBAL::die?难道不是使用它的全部意义吗?

1 个答案:

答案 0 :(得分:3)

die是Perl操作码(不是子例程)。它不能简单地被称为。 DBI和DBD模块的一部分是用C语言编写的,因此它们将无法使用die(无需像在解决方法中那样回调Perl代码)。

但你仍然可以挂钩$SIG{__DIE__}。就像文章所说的那样,GLOBAL::CORE::die用于“你真的需要捕获对die的调用”(而不是捕获异常被抛出)。