我正在使用 Perl 的 DBI 模块。我使用占位符准备一条语句,然后执行查询。
是否可以打印出执行的最终查询,而无需手动转义参数并将其放入占位符中?
谢谢
请参阅在 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
。
您可以使用 Statement 属性对准备好的语句进行调试打印。可以使用“语句句柄”或“数据库句柄”来访问它。
print $sth->{Statement} # with a statement handle
print $dbh->{Statement} # with a database handle
一般情况下不会,因为 DBI 不一定会产生这样的查询。如果您的数据库在其 API 中支持准备好的语句和占位符,DBI 会将它们传递给数据库并让数据库完成工作,这也是使用准备好的语句的原因之一。
这适用于禁用服务器端准备(默认)的
DBD::mysql
:
$ DBI_TRACE=2 perl your-script-here
它将打印每个语句两次,一次在绑定参数之前,一次在绑定参数之后。后者将是格式良好的 SQL,您可以自己运行。
还有一个模块,DBI::Log,它只打印 SQL 语句(没有其他调试噪音),以及可选的计时信息和调用者堆栈跟踪。真的很有用。
如果您不想创建自己的跟踪器模块(按照 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 实现依赖于 {'} 的处理。
正如 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 的准备/选择*/执行方法编写回调,并在其中收集您喜欢的任何内容。
对于大多数查询,最简单的调试是使用以下...
如果您使用
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});
对于 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";
}
放置:
$dbh->trace(2);
在准备和执行语句之前。这将输出大量调试信息,包括带有绑定值的 sql。
在生产环境中使用此功能时请务必小心,因为查询跟踪可能会泄露敏感信息,并且仅应用于调试或开发目的。