如何打印Perl的DBI填充占位符后执行的SQL查询?

问题描述 投票:0回答:9

我正在使用 Perl 的 DBI 模块。我使用占位符准备一条语句,然后执行查询。

是否可以打印出执行的最终查询,而无需手动转义参数并将其放入占位符中?

谢谢

mysql sql perl prepared-statement dbi
9个回答
17
投票

请参阅在 DBI 中跟踪。以下使用

DBD::SQLite
进行工作,但会产生大量输出:

$dbh->trace($dbh->parse_trace_flags('SQL|1|test'));

输出:

<- prepare('SELECT ... FROM ... WHERE ... = ?')= DBI::st=HASH(0x21ee924) at booklet-excel.pl line 213

<- execute('Inhaler')= '0E0' at booklet-excel.pl line 215

等等等等

您可以将自己的过滤器插入跟踪流以仅保留

prepare


11
投票

您可以使用 Statement 属性对准备好的语句进行调试打印。可以使用“语句句柄”或“数据库句柄”来访问它。

print $sth->{Statement} # with a statement handle

print $dbh->{Statement} # with a database handle

10
投票

一般情况下不会,因为 DBI 不一定会产生这样的查询。如果您的数据库在其 API 中支持准备好的语句和占位符,DBI 会将它们传递给数据库并让数据库完成工作,这也是使用准备好的语句的原因之一。


5
投票

这适用于禁用服务器端准备(默认)的

DBD::mysql

$ DBI_TRACE=2 perl your-script-here

它将打印每个语句两次,一次在绑定参数之前,一次在绑定参数之后。后者将是格式良好的 SQL,您可以自己运行。

还有一个模块,DBI::Log,它只打印 SQL 语句(没有其他调试噪音),以及可选的计时信息和调用者堆栈跟踪。真的很有用。


1
投票

如果您不想创建自己的跟踪器模块(按照 Sinan 的建议),您最好在将参数哈希传递给

$sth->execute()
之前尝试打印参数哈希。尤其如此,因为“Trace”功能依赖于 DBMS,并且
$sth->{Statement}
仅返回 SQL 占位符语句。这就是我所做的。

...
while (my $row = $csv->getline_hr($fh)) {
    my $cval = "";
    my $tquery = $query;
    foreach my $j (@cols) { 
            $cval = $row->{$j};
            $tquery =~ s/\?/\'$cval\'/;
    }
    print "$tquery\n\n";
    $rc = $sth->execute(@{$row}{@cols});
}

我使用 Text::CSV 的地方... 注意:这并不准确,因为 DBMS 实现依赖于 {'} 的处理。


1
投票

正如 Masto 所说,SQL 中的占位符通常不会直接替换为您的参数。参数化 SQL 的要点是将带有占位符的 SQL 传递给数据库引擎解析一次,然后它只接收参数。

正如 idssl 所指出的,您可以从语句或连接句柄获取 SQL,还可以从 ParamValues 检索参数。如果您不想自己执行此操作,您可以使用类似 DBIx::Log4perl 的工具来仅记录 SQL 和参数。请参阅 DBIX_L4P_LOG_DELAYBINDPARAM,其输出如下所示:

DEBUG - prepare(0.1): 'insert into mje values(?,?)'
DEBUG - $execute(0.1) = [{':p1' => 1,':p2' => 'fred'},undef];

当然,因为它使用 Log::Log4perl,如果您愿意,您可以省略“DEBUG - ”。有一个使用 DBIx::Log4perl 的小教程here

您应该能够将 DBIx::Log4perl 与任何 DBD 一起使用,如果您由于某种原因不能使用它,我会查看它。

如果您不想使用 DBIx::Log4perl 并且 DBI 跟踪选项不适合您的需求,您可以为 DBI 的准备/选择*/执行方法编写回调,并在其中收集您喜欢的任何内容。


1
投票

对于大多数查询,最简单的调试是使用以下...

  • 如果您使用

    do
    方法准备并执行单个语句,请使用:

     use feature 'say';
     say $dbh->{Statement};
    
  • 如果分别使用

    prepare
    execute
    方法,请使用:

     use feature 'say';
     use Data::Dumper;
     $Data::Dumper::Sortkeys = 1;
     say $sth->{Statement};
     say Dumper($sth->{ParamValues});
    

0
投票

对于 Perl 新手,我的解决方案是从 not2qubit 复制并简化/希望变得更通用/可重用:

sub dump_query {
  my $tquery = shift;
  my @args = shift;
  my $j;
    foreach my $j (@args) { $tquery =~ s/\?/\'$j\'/; }
    print STDERR "$tquery\n\n";
}

0
投票

放置:

$dbh->trace(2);

在准备和执行语句之前。这将输出大量调试信息,包括带有绑定值的 sql。

在生产环境中使用此功能时请务必小心,因为查询跟踪可能会泄露敏感信息,并且仅应用于调试或开发目的。

© www.soinside.com 2019 - 2024. All rights reserved.