Как я могу напечатать запрос 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});