Perl 如何在子类DBI中拦截查询?

Perl 如何在子类DBI中拦截查询?,perl,dbi,Perl,Dbi,我需要截取所有查询(比如说,为了进行结构化日志记录)。 该应用程序已经使用了一个子类DBI,所以我希望我可以将需要的代码注入execute重载MyDB::st类中 显然,这是不够的 在下面的示例中,MyDB::st::execute仅在示例2中执行)。它不在1)我调用do的地方执行,也不在3)我调用selectrow\u array的地方执行(即使文档中说selectrow\u array组合了prepare、execute和fetchrow\u hashref) 我是否也需要重载MyDB::d

我需要截取所有查询(比如说,为了进行结构化日志记录)。 该应用程序已经使用了一个子类DBI,所以我希望我可以将需要的代码注入
execute
重载
MyDB::st
类中

显然,这是不够的

在下面的示例中,
MyDB::st::execute
仅在示例2中执行)。它不在1)我调用
do
的地方执行,也不在3)我调用
selectrow\u array
的地方执行(即使文档中说
selectrow\u array
组合了
prepare
execute
fetchrow\u hashref

我是否也需要重载
MyDB::db
类中的语句?有很多(
do
selectrow\u array
selectrow\u arrayref
selectrow\u hashref
selectall\u arrayref
selectall\u hashref
selectcol\u arrayref
),等等),我希望能避免这种情况

为了简单起见,该示例使用SQLite,但我检查的其他驱动程序的工作原理相同

#!/usr/bin/perl

package MyDB;
use strict;
use warnings;
use base 'DBI';

sub connect {
    return DBI::connect( 'MyDB', 'dbi:SQLite:dbname=so.sqlite', '', '',);
}


package MyDB::db;
use strict;
use warnings;
use base 'DBI::db';

sub prepare {
    my $self = shift;
    warn "  DB: PREPARE\n";
    return $self->SUPER::prepare( @_ );
}


package MyDB::st;
use strict;
use warnings;
use base 'DBI::st';

sub execute {
    my $self = shift;
    warn "  ST: EXECUTE\n";
    return $self->SUPER::execute( @_ );
}

sub fetchrow_hashref {
    my $self = shift;
    warn "  ST: FETCHROW_HASHREF\n";
    return $self->SUPER::fetchrow_hashref( @_ );
}




package main;
use strict;
use warnings;

my $dbh = MyDB::connect();

warn "1) --- DO ---\n";
$dbh->do("CREATE TABLE IF NOT EXISTS ttt (a int)");

warn "2) --- PREPARE/EXECUTE/FETCHROW_HASHREF ---\n";
my $sth = $dbh->prepare( "SELECT * FROM ttt" );
$sth->execute();
$sth->fetchrow_hashref();

warn "3) --- SELECTROW_ARRAY ---\n";
$dbh->selectrow_array( "SELECT * FROM ttt" );

如果您只想做日志查询,则不需要拦截任何内容。尝试设置
DBI\u TRACE
环境变量

DBI_TRACE=1=dbitrace.log

其中
1
是日志级别,第二个参数是日志文件的路径。请参阅和

如果您只想进行日志查询,则无需拦截任何内容。尝试设置
DBI\u TRACE
环境变量

DBI_TRACE=1=dbitrace.log

其中
1
是日志级别,第二个参数是日志文件的路径。请参阅和

虽然文档中用其他方法描述了某些方法,但文档并未声称这些方法调用了其他方法

通过使用DBI提供的模板,每个驱动程序都提供了许多DBI方法的自己的实现(例如,
selectrow\u array
)。用C编写,模板中方法的实现经常直接调用驱动程序的函数,而不是通过DBI方法调用间接调用它们

这使得调用速度更快,但正如您所发现的,这使得扩展DBI变得更加困难

您可以找到
DBI.pm
中列出的所有方法的Perl实现。复制这些。这些实现都是根据以下方法定义的,限制了您必须更改的内容:

  • 准备
  • 执行
  • fetch
  • fetchrow\u hashref
  • fetchrow\u arrayref
  • bind\u col

虽然本文档从其他方法的角度描述了某些方法,但并未声称这些方法调用了其他方法

通过使用DBI提供的模板,每个驱动程序都提供了许多DBI方法的自己的实现(例如,
selectrow\u array
)。用C编写,模板中方法的实现经常直接调用驱动程序的函数,而不是通过DBI方法调用间接调用它们

这使得调用速度更快,但正如您所发现的,这使得扩展DBI变得更加困难

您可以找到
DBI.pm
中列出的所有方法的Perl实现。复制这些。这些实现都是根据以下方法定义的,限制了您必须更改的内容:

  • 准备
  • 执行
  • fetch
  • fetchrow\u hashref
  • fetchrow\u arrayref
  • bind\u col

最好说清楚您计划做什么,因为(例如)DBD::SQlite已经具备了记录语句的功能,所以没有理由拦截查询。IIRC类似于
$dbh->sqlite\u trace=1
DBI
对包做了一些奇怪的事情。我更希望看到需要挂接的操作的简单包装,而不是试图覆盖继承的方法。@ChrisTurner-我需要以结构化的方式转储一些数据(查询、执行时间、一些有关程序状态的信息)。最好确切地说一下您计划做什么,因为(例如),SQlite已经具备了记录语句的能力,所以没有理由拦截查询。IIRC类似于
$dbh->sqlite\u trace=1
DBI
对包做了一些奇怪的事情。我更希望看到需要挂接的操作的简单包装,而不是试图覆盖继承的方法。@ChrisTurner-我需要以结构化的方式转储一些数据(查询、执行时间、一些有关程序状态的信息)。我知道
DBI_TRACE
,但解析日志实际上不是一个选项。我想转储一些结构化数据,如查询字符串、执行时间、perl调用堆栈和一些有关程序状态的信息。我知道
DBI_TRACE
,但解析日志实际上不是一个选项。我想转储一些结构化数据,例如查询字符串、执行时间、perl调用堆栈以及一些有关程序状态的信息。