diff --git a/C4/Reports/Guided.pm b/C4/Reports/Guided.pm index 577b369495..639608dacc 100644 --- a/C4/Reports/Guided.pm +++ b/C4/Reports/Guided.pm @@ -54,6 +54,7 @@ use Koha::Logger; use Koha::Notice::Templates; use Koha::Patron::Categories; use Koha::Patrons; +use Koha::Report; use Koha::Reports; use Koha::SharedContent; use Koha::TemplateUtils qw( process_tt ); @@ -604,6 +605,7 @@ sub execute_query { my ( $is_sql_valid, $errors ) = Koha::Report->new( { savedsql => $sql } )->is_sql_valid; return ( undef, @{$errors}[0] ) unless $is_sql_valid; + $sql = Koha::Report->apply_execution_time_limit($sql); foreach my $sql_param (@$sql_params) { if ( $sql_param =~ m/\n/ ) { diff --git a/Koha/Report.pm b/Koha/Report.pm index b6a210eb9f..c41feff26c 100644 --- a/Koha/Report.pm +++ b/Koha/Report.pm @@ -258,6 +258,38 @@ sub _might_add_limit { return $sql; } +=head3 apply_execution_time_limit + + $sql = Koha::Report->apply_execution_time_limit($sql); + +Apply SQL execution time limits based on report_sql_max_statement_time_seconds. + +=cut + +sub apply_execution_time_limit { + my ( $class, $sql ) = @_; + + # https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=39164 + my $report_sql_max_statement_time_seconds = C4::Context->config('report_sql_max_statement_time_seconds') // 0; + if ($report_sql_max_statement_time_seconds) { + my %versions = C4::Context::get_versions(); + if ( $versions{'mysqlVersion'} =~ /MariaDB/i ) { + $sql = sprintf( + 'SET STATEMENT max_statement_time=%f FOR %s', + $report_sql_max_statement_time_seconds, + $sql + ); + } else { + + # mysql timing is in milliseconds + $report_sql_max_statement_time_seconds *= 1000; + $sql =~ s#select#select /*+ MAX_EXECUTION_TIME($report_sql_max_statement_time_seconds) */#i; + } + } + + return $sql; +} + =head3 _type Returns name of corresponding DBIC resultset diff --git a/t/db_dependent/Koha/Reports.t b/t/db_dependent/Koha/Reports.t index 19d1d60679..6125a64f69 100755 --- a/t/db_dependent/Koha/Reports.t +++ b/t/db_dependent/Koha/Reports.t @@ -18,7 +18,7 @@ use Modern::Perl; use Test::NoWarnings; -use Test::More tests => 9; +use Test::More tests => 10; use Koha::Report; use Koha::Reports; @@ -185,4 +185,29 @@ subtest '_might_add_limit' => sub { ); }; +subtest 'apply_execution_time_limit' => sub { + plan tests => 3; + + my $sql = "SELECT * FROM biblio"; + + t::lib::Mocks::mock_config( 'report_sql_max_statement_time_seconds', 0 ); + is( Koha::Report->apply_execution_time_limit($sql), $sql, 'No execution time limit configured' ); + + t::lib::Mocks::mock_config( 'report_sql_max_statement_time_seconds', 1.5 ); + my $context = Test::MockModule->new('C4::Context'); + $context->mock( 'get_versions', sub { return ( mysqlVersion => '10.6.0-MariaDB' ); } ); + is( + Koha::Report->apply_execution_time_limit($sql), + 'SET STATEMENT max_statement_time=1.500000 FOR SELECT * FROM biblio', + 'MariaDB max statement time applied' + ); + + $context->mock( 'get_versions', sub { return ( mysqlVersion => '8.0.36' ); } ); + like( + Koha::Report->apply_execution_time_limit($sql), + qr!^(?i:select) /\*\+ MAX_EXECUTION_TIME\(1500\) \*/ \* FROM biblio$!, + 'MySQL max execution time hint applied' + ); +}; + $schema->storage->txn_rollback;