Bug 26669: Last Run if report not always updated

The last run of a report is updated only if method execute_query() is
called with report_id.
This whas missing for :
- when report is run publicly
- when report is sent by email
- when report is exported

Patch changes the method signature to use a hash of params, in order to
easily avoid some params.

Test plan :

1) Create a report.
2) Run report.
3) Check the report listing.  Confirm that the last run info on the report is updated.
4) Make report public.
5) Run report via public url.
6) Check the report listing.  Confirm that the last run info on the report IS NOT updated.
7) Schedule the report to run at a given time and e-mailed to an address.
8) After the report runs at the scheduled time, check the report listing.  Confirm that the last run info on the report IS NOT updated.
9) Run report.
10) Export results.
11) Check the report listing.  Confirm that the last run info on the report IS NOT updated AT THE TIME OF THE EXPORT.

Questionable (I don't know if this is addressed):
12) Run report on backend through a cron job and send results via e-mail.
13) Check the report listing.  Confirm that the last run info on the report IS NOT updated.

14) Apply patch.
15) Rerun steps 2-13.  Confirm that steps 3, 6, 8, 11, and 13 DO UPDATE the last run info.

Signed-off-by: Séverine Queune <severine.queune@bulac.fr>

Signed-off-by: Séverine Queune <severine.queune@bulac.fr>

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Fridolin Somers <fridolin.somers@biblibre.com>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
This commit is contained in:
Fridolin Somers 2021-01-14 16:46:25 +01:00 committed by Kyle Hall
parent aeb6034ea9
commit 23cf6dd767
6 changed files with 68 additions and 27 deletions

View file

@ -541,17 +541,18 @@ sub strip_limit {
sub execute_query { sub execute_query {
my ( $sql, $offset, $limit, $sql_params, $report_id ) = @_; my $params = shift;
my $sql = $params->{sql};
$sql_params = [] unless defined $sql_params; my $offset = $params->{offset} || 0;
my $limit = $params->{limit} || 999999;
my $sql_params = defined $params->{sql_params} ? $params->{sql_params} : [];
my $report_id = $params->{report_id};
# check parameters # check parameters
unless ($sql) { unless ($sql) {
carp "execute_query() called without SQL argument"; carp "execute_query() called without SQL argument";
return; return;
} }
$offset = 0 unless $offset;
$limit = 999999 unless $limit;
Koha::Logger->get->debug("Report - execute_query($sql, $offset, $limit)"); Koha::Logger->get->debug("Report - execute_query($sql, $offset, $limit)");
@ -1050,7 +1051,8 @@ sub EmailReport {
my $sql = $report->savedsql; my $sql = $report->savedsql;
return ( { FATAL => "NO_REPORT" } ) unless $sql; return ( { FATAL => "NO_REPORT" } ) unless $sql;
my ( $sth, $errors ) = execute_query( $sql ); #don't pass offset or limit, hardcoded limit of 999,999 will be used #don't pass offset or limit, hardcoded limit of 999,999 will be used
my ( $sth, $errors ) = execute_query( { sql => $sql, report_id => $report_id } );
return ( undef, [{ FATAL => "REPORT_FAIL" }] ) if $errors; return ( undef, [{ FATAL => "REPORT_FAIL" }] ) if $errors;
my $counter = 1; my $counter = 1;

View file

@ -269,7 +269,13 @@ foreach my $report_id (@ARGV) {
my $params_needed = ( $sql =~ s/(<<[^>]+>>)/\?/g ); my $params_needed = ( $sql =~ s/(<<[^>]+>>)/\?/g );
die("You supplied ". scalar @params . " parameter(s) and $params_needed are required by the report") if scalar @params != $params_needed; die("You supplied ". scalar @params . " parameter(s) and $params_needed are required by the report") if scalar @params != $params_needed;
my ($sth) = execute_query( $sql, undef, undef, \@params, $report_id ); my ($sth) = execute_query(
{
sql => $sql,
sql_params => \@params,
report_id => $report_id,
}
);
my $count = scalar($sth->rows); my $count = scalar($sth->rows);
unless ($count) { unless ($count) {
print "NO OUTPUT: 0 results from execute_query\n"; print "NO OUTPUT: 0 results from execute_query\n";

View file

@ -58,13 +58,18 @@ if ($cache_active) {
} }
unless ($json_text) { unless ($json_text) {
my $offset = 0;
my $limit = C4::Context->preference("SvcMaxReportRows") || 10; my $limit = C4::Context->preference("SvcMaxReportRows") || 10;
my ( $sql, undef ) = $report_rec->prep_report( \@param_names, \@sql_params ); my ( $sql, undef ) = $report_rec->prep_report( \@param_names, \@sql_params );
my ( $sth, $errors ) = my ( $sth, $errors ) = execute_query(
execute_query( $sql, $offset, $limit, undef, $report_id ); {
sql => $sql,
offset => 0,
limit => $limit,
report_id => $report_id,
}
);
if ($sth) { if ($sth) {
my $lines; my $lines;
if ($report_annotation) { if ($report_annotation) {

View file

@ -821,7 +821,14 @@ elsif ($phase eq 'Run this report'){
} else { } else {
my ($sql,$header_types) = $report->prep_report( \@param_names, \@sql_params ); my ($sql,$header_types) = $report->prep_report( \@param_names, \@sql_params );
$template->param(header_types => $header_types); $template->param(header_types => $header_types);
my ( $sth, $errors ) = execute_query( $sql, $offset, $limit, undef, $report_id ); my ( $sth, $errors ) = execute_query(
{
sql => $sql,
offset => $offset,
limit => $limit,
report_id => $report_id,
}
);
my $total; my $total;
if (!$sth) { if (!$sth) {
die "execute_query failed to return sth for report $report_id: $sql"; die "execute_query failed to return sth for report $report_id: $sql";
@ -834,7 +841,7 @@ elsif ($phase eq 'Run this report'){
push @rows, { cells => \@cells }; push @rows, { cells => \@cells };
} }
if( $want_full_chart ){ if( $want_full_chart ){
my ($sth2, $errors2) = execute_query($sql); my ( $sth2, $errors2 ) = execute_query( { sql => $sql, report_id => $report_id } );
while (my $row = $sth2->fetchrow_arrayref()) { while (my $row = $sth2->fetchrow_arrayref()) {
my @cells = map { +{ cell => $_ } } @$row; my @cells = map { +{ cell => $_ } } @$row;
push @allrows, { cells => \@cells }; push @allrows, { cells => \@cells };
@ -888,7 +895,7 @@ elsif ($phase eq 'Export'){
my $reportfilename = $reportname ? "$reportname-reportresults.$format" : "reportresults.$format" ; my $reportfilename = $reportname ? "$reportname-reportresults.$format" : "reportresults.$format" ;
($sql, undef) = $report->prep_report( \@param_names, \@sql_params ); ($sql, undef) = $report->prep_report( \@param_names, \@sql_params );
my ($sth, $q_errors) = execute_query($sql); my ( $sth, $q_errors ) = execute_query( { sql => $sql, report_id => $report_id } );
unless ($q_errors and @$q_errors) { unless ($q_errors and @$q_errors) {
my ( $type, $content ); my ( $type, $content );
if ($format eq 'tab') { if ($format eq 'tab') {

View file

@ -61,12 +61,18 @@ if ($cache_active) {
} }
unless ($json_text) { unless ($json_text) {
my $offset = 0;
my $limit = C4::Context->preference("SvcMaxReportRows") || 10; my $limit = C4::Context->preference("SvcMaxReportRows") || 10;
my ( $sql, undef ) = $report_rec->prep_report( \@param_names, \@sql_params ); my ( $sql, undef ) = $report_rec->prep_report( \@param_names, \@sql_params );
my ( $sth, $errors ) = execute_query( $sql, $offset, $limit, undef, $report_id ); my ( $sth, $errors ) = execute_query(
{
sql => $sql,
offset => 0,
limit => $limit,
report_id => $report_id,
}
);
if ($sth) { if ($sth) {
my $lines; my $lines;
if ($report_annotation) { if ($report_annotation) {

View file

@ -238,16 +238,24 @@ subtest 'get_saved_reports' => sub {
is( scalar @{ get_saved_reports() }, is( scalar @{ get_saved_reports() },
$count, "Report2 and report3 have been deleted" ); $count, "Report2 and report3 have been deleted" );
my $sth = execute_query('SELECT COUNT(*) FROM systempreferences', 0, 10); my $sth = execute_query(
{
sql => 'SELECT COUNT(*) FROM systempreferences',
offset => 0,
limit => 10,
}
);
my $results = $sth->fetchall_arrayref; my $results = $sth->fetchall_arrayref;
is(scalar @$results, 1, 'running a query returned a result'); is(scalar @$results, 1, 'running a query returned a result');
my $version = C4::Context->preference('Version'); my $version = C4::Context->preference('Version');
$sth = execute_query( $sth = execute_query(
'SELECT value FROM systempreferences WHERE variable = ?', {
0, sql => 'SELECT value FROM systempreferences WHERE variable = ?',
10, offset => 0,
[ 'Version' ], limit => 10,
sql_params => ['Version'],
}
); );
$results = $sth->fetchall_arrayref; $results = $sth->fetchall_arrayref;
is_deeply( is_deeply(
@ -258,9 +266,16 @@ subtest 'get_saved_reports' => sub {
# for next test, we want to let execute_query capture any SQL errors # for next test, we want to let execute_query capture any SQL errors
my $errors; my $errors;
warning_like {local $dbh->{RaiseError} = 0; ($sth, $errors) = execute_query( warning_like {
'SELECT surname FRM borrowers', # error in the query is intentional local $dbh->{RaiseError} = 0;
0, 10 ) } ( $sth, $errors ) = execute_query(
{
sql => 'SELECT surname FRM borrowers', # error in the query is intentional
offset => 0,
limit => 10,
}
)
}
qr/DBD::mysql::st execute failed: You have an error in your SQL syntax;/, qr/DBD::mysql::st execute failed: You have an error in your SQL syntax;/,
"Wrong SQL syntax raises warning"; "Wrong SQL syntax raises warning";
ok( ok(
@ -287,14 +302,14 @@ subtest 'Ensure last_run is populated' => sub {
is( $report->last_run, undef, 'Newly created report has null last_run ' ); is( $report->last_run, undef, 'Newly created report has null last_run ' );
execute_query( $report->savedsql, undef, undef, undef, $report->id ); execute_query( { sql => $report->savedsql, report_id => $report->id } );
$report->discard_changes(); $report->discard_changes();
isnt( $report->last_run, undef, 'First run of report populates last_run' ); isnt( $report->last_run, undef, 'First run of report populates last_run' );
my $previous_last_run = $report->last_run; my $previous_last_run = $report->last_run;
sleep(1); # last_run is stored to the second, so we need to ensure at least one second has passed between runs sleep(1); # last_run is stored to the second, so we need to ensure at least one second has passed between runs
execute_query( $report->savedsql, undef, undef, undef, $report->id ); execute_query( { sql => $report->savedsql, report_id => $report->id } );
$report->discard_changes(); $report->discard_changes();
isnt( $report->last_run, $previous_last_run, 'Second run of report updates last_run' ); isnt( $report->last_run, $previous_last_run, 'Second run of report updates last_run' );