Как я могу напечатать запрос SQL, выполняемый после заполнения Perl DBI в заполнителях?
Я использую модуль Perl DBI. Я готовлю оператор с использованием заполнителей, затем выполняю запрос.
Можно ли распечатать окончательный запрос, который был выполнен без ручного экранирования параметров и отбрасывания их в заполнители?
Спасибо
Ответы
Ответ 1
Смотрите Трассировка в 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
.
Ответ 2
В общем случае, поскольку DBI не обязательно создает такой запрос. Если ваша база данных поддерживает подготовленные операторы и заполнители в своем API, DBI передаст их и позволит базе данных выполнить эту работу, что является одной из причин использования подготовленных операторов.
Ответ 3
Вы можете выполнить отладочную распечатку подготовленного оператора, используя атрибут Statement. Доступ к нему можно получить либо с помощью дескриптора инструкции, либо с помощью дескриптора базы данных.
print $sth->{Statement} # with a statement handle
print $dbh->{Statement} # with a database handle
Ответ 4
Это работает для DBD::mysql
с отключенной подготовкой на стороне сервера (по умолчанию):
$ DBI_TRACE=2 perl your-script-here
Он будет печатать каждое утверждение дважды, один раз перед привязкой параметров и один раз после. Последний будет правильно сформированным SQL, который вы можете запустить самостоятельно.
Существует также модуль DBI :: Log, который печатает только операторы SQL (без других помех отладки), а также необязательную информацию о синхронизации и трассировку стека вызовов. Это действительно полезно.
Ответ 5
Как говорит 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 и собирать все, что вам нравится.
Ответ 6
Если вы не хотите создавать свой собственный трассировочный модуль (как предложено Синаном), вам лучше просто попытаться распечатать хэш-аргумент, прежде чем он будет передан в $sth->execute()
. Это особенно верно, поскольку функциональность "Trace" зависит от СУБД, а $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...
ПРИМЕЧАНИЕ. Это не точно, из-за зависимостей реализации СУБД от {'} s.
Ответ 7
Для большинства запросов самая простая отладка - использовать следующее...
Если вы готовите и выполняете один оператор с использованием метода do
, используйте:
use feature 'say';
say $dbh->{Statement};
Если вы используете методы prepare
и execute
по отдельности, используйте:
use feature 'say';
use Data::Dumper;
say $sth->{Statement};
say Dumper($sth->{ParamValues});