【问题标题】:Capture NOTICE from PostgreSQL in Perl DBI在 Perl DBI 中从 PostgreSQL 捕获 NOTICE
【发布时间】: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。

有什么想法吗?

【问题讨论】:

    标签: postgresql perl error-handling


    【解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-03
      • 2016-02-05
      • 2015-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-28
      • 1970-01-01
      相关资源
      最近更新 更多