在 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
,而$stderr
有to STDERR
后跟a warn-ing
。因此,您的数据库代码将进入这样的块中,并且 NOTICE 应该在该 $stderr
变量中结束。如果您希望仅以这种方式捕获,还有一个 capture_stderr
函数。
【讨论】:
通过$SIG__WARN__
捕获有效。谢谢!
@GeneVincent 太好了——感谢您让我知道。 (那么我希望该模块也可以捕获它。虽然使用 $SIG__WARN__
不需要更改其他代码,但可能与范围相关的调整除外。)【参考方案2】:
这似乎无法正常工作,它被识别为unsolved bug。
【讨论】:
以上是关于在 Perl DBI 中从 PostgreSQL 捕获 NOTICE的主要内容,如果未能解决你的问题,请参考以下文章
在 Windows-7-x64 上使用 DBI Perl 和 MySql 的未定义 $DBI::errstr