在 Perl DBI 中从 PostgreSQL 捕获 NOTICE

Posted

技术标签:

【中文标题】在 Perl DBI 中从 PostgreSQL 捕获 NOTICE【英文标题】:Capture NOTICE from PostgreSQL in Perl DBI 【发布时间】:2022-01-19 07:12:37 【问题描述】:

我在 PostgreSQL 表上使用全文搜索和用户生成的输入,在本例中为“a”。

my $dbh = DBI->connect("...",  RaiseError => 0, AutoCommit => 1 );
my $sth = $dbh->prepare("SELECT name from mytable WHERE tsv @@ plainto_tsquery('the a')");
my $rv = $sth->execute();

如果用户输入只包含停用词,我会收到关于 STDERR 的通知,并且查询不会返回任何结果,但不会产生错误。

我想在 Perl 中捕获该 NOTICE 以提醒用户重新搜索,但我似乎无法访问它。

将 RaiseError 设置为 1 不会改变任何内容,并且 $dbh->pg_notifies 返回 undef。

有什么想法吗?

【问题讨论】:

【参考方案1】:

我认为提到“NOTICE”意味着某事做了RAISE。它的行为方式是configurable,但深入研究需要更多细节。

在 perl 级别,有多种方法可以访问 STDERR 流并捕获发送给它的内容。

如果这些是warn-ings,那么为$SIG__WARN__ 设置一个挂钩会在要打印警告时运行该子例程


    local $SIG__WARN__ = sub  say "Got warning: $_[0]"; ;

    warn "a warning";

所以你可以用这种方式捕捉它,用它做你想做的事,然后也许会重新发送。示例中的$_[0] 具有字符串a warning,并且在匿名子程序运行后,在发出警告后控制返回到下一行(此sn-p 中的warn 语句)。见%SIG。

我把它放在一个块中只是为了能够local-ize 对SIG__WARN__ 的更改,这实际上是强制性的(如果这个全局不是local-ized 它的更改会影响所有代码)。因此,如果这段代码无论如何都在合适的词法范围内,则不需要该块。

但这不会捕获直接打印到STDERR 的内容。为此,最实用的方法是使用库,一个简单方便的方法是Capture::Tiny

use Capture::Tiny qw(capture);

my ($stdout, $stderr, $exit) = capture  
    say "to STDOUT"; 
    say STDERR "to STDERR"; 
    warn "a warn-ing"; 
    # ...
;

现在$stdout 有文本to STDOUT,而$stderrto STDERR 后跟a warn-ing。因此,您的数据库代码将进入这样的块中,并且 NOTICE 应该在该 $stderr 变量中结束。如果您希望仅以这种方式捕获,还有一个 capture_stderr 函数。

【讨论】:

通过$SIG__WARN__ 捕获有效。谢谢! @GeneVincent 太好了——感谢您让我知道。 (那么我希望该模块也可以捕获它。虽然使用 $SIG__WARN__ 不需要更改其他代码,但可能与范围相关的调整除外。)【参考方案2】:

这似乎无法正常工作,它被识别为unsolved bug。

【讨论】:

以上是关于在 Perl DBI 中从 PostgreSQL 捕获 NOTICE的主要内容,如果未能解决你的问题,请参考以下文章

Linux中perl-DBI和DBI有啥区别?

在 Windows-7-x64 上使用 DBI Perl 和 MySql 的未定义 $DBI::errstr

Perl/DBI/FreeTDS/SQLAzure 一些插入被忽略

Perl 执行 DBI 循环执行

perl 中的 DBD::Oracle 和 DBI 错误

为啥这个 ISQL 命令不能通过 Perl 的 DBI 运行?