我正在使用 Perl 的 DBI 模块。我使用占位符准备一个语句,然后执行查询。
是否可以在不手动转义参数并将它们放入占位符的情况下打印出执行的最终查询?
谢谢
我正在使用 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
s。
您可以使用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 语句(没有其他调试噪音),以及可选的时间信息和调用者堆栈跟踪。这真的很有用。
正如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 的小教程。
您应该能够将 DBIx::Log4perl 与任何 DBD 一起使用,如果由于某种原因您不能 RT 它,我会看看它。
如果您不想使用 DBIx::Log4perl 并且 DBI 跟踪选项不适合您的需要,您可以为 DBI 的 prepare/select*/execute 方法编写回调并在其中收集您喜欢的任何内容。
如果您不想创建自己的跟踪器模块(如 Sinan 建议的那样),最好在将参数哈希传递给$sth->execute()
. 尤其如此,因为“跟踪”功能依赖于 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 实现依赖于 {'}s 的处理。
对于大多数查询,最简单的调试是使用以下...
如果您使用方法准备并执行单个语句do
,请使用:
use feature 'say';
say $dbh->{Statement};
如果您单独使用prepare
和execute
方法,请使用:
use feature 'say';
use Data::Dumper;
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";
}