【问题标题】:How can I print the SQL query executed after Perl's DBI fills in the placeholders?如何打印 Perl 的 DBI 填充占位符后执行的 SQL 查询?
【发布时间】:2010-12-13 19:43:59
【问题描述】:

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

是否可以在不手动转义参数并将其放入占位符的情况下打印出执行的最终查询?

谢谢

【问题讨论】:

  • @Jake 这个问题比另一个问题早 4 年被问到,这个问题也有更好的答案,(在我看来)。这就是为什么我将另一个问题标记为重复和候选关闭。

标签: mysql sql perl prepared-statement dbi


【解决方案1】:

Tracing in 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

等等等等

您可以plug your own filter in to the trace stream 只保留prepares。

【讨论】:

  • 赞成教我有关跟踪的知识,即使它没有回答问题(因为正如其他人指出的那样,这是不可能的)。之所以发表此评论,是因为我为提出一个我知道并不能回答问题的答案而感到内疚。大声笑:$
【解决方案2】:

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

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

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

【讨论】:

  • 这只是返回传递给最后一个preparedo的字符串,因此占位符不会按照OP的要求填写。
  • 可以使用 print Dumper( $statement_handle->{'ParamValues'} ); 单独打印绑定参数 - 可能足以调试大多数查询。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    这适用于 DBD::mysql 禁用服务器端准备(默认):

    $ DBI_TRACE=2 perl your-script-here
    

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

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

    【讨论】:

    • 最佳答案在这里!
    【解决方案5】:

    如果您不想创建自己的跟踪器模块(如 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 实现。

    【讨论】:

      【解决方案6】:

      正如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 一起使用,如果由于某种原因您不能 RT,我会查看它。

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

      【讨论】:

        【解决方案7】:

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

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

          use feature 'say';
          say $dbh->{Statement};
          
        • 如果您分别使用prepareexecute 方法,请使用:

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

        【讨论】:

          【解决方案8】:

          对于 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";
          }
          

          【讨论】:

            猜你喜欢
            • 2014-01-28
            • 2015-08-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-12-22
            • 1970-01-01
            • 2014-01-25
            • 1970-01-01
            相关资源
            最近更新 更多