diff --git a/libraries/classes/Sql.php b/libraries/classes/Sql.php index d2c1a248fd..7a7df197c7 100644 --- a/libraries/classes/Sql.php +++ b/libraries/classes/Sql.php @@ -24,7 +24,9 @@ use PhpMyAdmin\SqlParser\Utils\Query; use PhpMyAdmin\Utils\ForeignKey; use function __; +use function array_column; use function array_keys; +use function array_sum; use function bin2hex; use function ceil; use function count; @@ -247,36 +249,41 @@ class Sql * @psalm-param non-empty-list $profilingResults * * @psalm-return array{ - * total_time: int|float, - * states: array}>, - * chart: array, + * total_time: float, + * states: array}>, + * chart: array, * profile: list - * } + * }|array{} */ private function getDetailedProfilingStats(array $profilingResults): array { - $profiling = ['total_time' => 0, 'states' => [], 'chart' => [], 'profile' => []]; + $totalTime = (float) array_sum(array_column($profilingResults, 'Duration')); + if ($totalTime === 0.0) { + return []; + } - foreach ($profilingResults as $oneResult) { - $status = ucwords($oneResult['Status']); - $profiling['total_time'] += $oneResult['Duration']; - $profiling['profile'][] = [ + $states = []; + $chart = []; + $profile = []; + foreach ($profilingResults as $result) { + $status = ucwords($result['Status']); + $profile[] = [ 'status' => $status, - 'duration' => Util::formatNumber($oneResult['Duration'], 3, 1), - 'duration_raw' => $oneResult['Duration'], + 'duration' => Util::formatNumber($result['Duration'], 3, 1), + 'duration_raw' => $result['Duration'], ]; - if (! isset($profiling['states'][$status])) { - $profiling['states'][$status] = ['total_time' => $oneResult['Duration'], 'calls' => 1]; - $profiling['chart'][$status] = $oneResult['Duration']; + if (! isset($states[$status])) { + $states[$status] = ['total_time' => (float) $result['Duration'], 'calls' => 1]; + $chart[$status] = (float) $result['Duration']; } else { - $profiling['states'][$status]['calls']++; - $profiling['states'][$status]['total_time'] += $oneResult['Duration']; - $profiling['chart'][$status] += $oneResult['Duration']; + $states[$status]['calls']++; + $states[$status]['total_time'] += $result['Duration']; + $chart[$status] += $result['Duration']; } } - return $profiling; + return ['total_time' => $totalTime, 'states' => $states, 'chart' => $chart, 'profile' => $profile]; } /** @@ -1021,7 +1028,9 @@ class Sql $scripts->addFile('sql.js'); $profiling = $this->getDetailedProfilingStats($profilingResults); - $profilingChart = $this->template->render('sql/profiling_chart', ['profiling' => $profiling]); + if ($profiling !== []) { + $profilingChart = $this->template->render('sql/profiling_chart', ['profiling' => $profiling]); + } } $bookmark = ''; @@ -1441,7 +1450,9 @@ class Sql $profilingChartHtml = ''; if ($profilingResults !== []) { $profiling = $this->getDetailedProfilingStats($profilingResults); - $profilingChartHtml = $this->template->render('sql/profiling_chart', ['profiling' => $profiling]); + if ($profiling !== []) { + $profilingChartHtml = $this->template->render('sql/profiling_chart', ['profiling' => $profiling]); + } } $missingUniqueColumnMessage = $this->getMessageIfMissingColumnIndex($table, $db, $editable, $hasUnique); diff --git a/test/classes/SqlTest.php b/test/classes/SqlTest.php index 4f0aea68ff..8bc11d9f9f 100644 --- a/test/classes/SqlTest.php +++ b/test/classes/SqlTest.php @@ -617,10 +617,17 @@ class SqlTest extends AbstractTestCase public function testGetDetailedProfilingStatsWithoutData(): void { $method = new ReflectionMethod($this->sql, 'getDetailedProfilingStats'); - $this->assertSame( - ['total_time' => 0, 'states' => [], 'chart' => [], 'profile' => []], - $method->invoke($this->sql, []), - ); + $this->assertSame([], $method->invoke($this->sql, [])); + } + + public function testGetDetailedProfilingStatsWithZeroTotalTime(): void + { + $method = new ReflectionMethod($this->sql, 'getDetailedProfilingStats'); + $profiling = [ + ['Status' => 'Starting', 'Duration' => '0'], + ['Status' => 'checking permissions', 'Duration' => '0'], + ]; + $this->assertSame([], $method->invoke($this->sql, $profiling)); } public function testGetDetailedProfilingStatsWithData(): void @@ -659,50 +666,50 @@ class SqlTest extends AbstractTestCase $expected = [ 'total_time' => 0.000299, 'states' => [ - 'Starting' => ['total_time' => '0.000017', 'calls' => 1], - 'Checking Permissions' => ['total_time' => '0.000003', 'calls' => 1], + 'Starting' => ['total_time' => 0.000017, 'calls' => 1], + 'Checking Permissions' => ['total_time' => 0.000003, 'calls' => 1], 'Opening Tables' => ['total_time' => 0.00016, 'calls' => 2], - 'After Opening Tables' => ['total_time' => 6.0E-6, 'calls' => 2], - 'System Lock' => ['total_time' => 4.0E-6, 'calls' => 2], - 'Table Lock' => ['total_time' => 1.5E-5, 'calls' => 2], - 'Unlocking Tables' => ['total_time' => 4.0E-6, 'calls' => 2], - 'Closing Tables' => ['total_time' => 9.0E-6, 'calls' => 3], - 'Init' => ['total_time' => '0.000007', 'calls' => 1], - 'Optimizing' => ['total_time' => '0.000004', 'calls' => 1], - 'Statistics' => ['total_time' => '0.000006', 'calls' => 1], - 'Preparing' => ['total_time' => '0.000006', 'calls' => 1], - 'Executing' => ['total_time' => '0.000002', 'calls' => 1], - 'Sending Data' => ['total_time' => '0.000029', 'calls' => 1], - 'End Of Update Loop' => ['total_time' => '0.000003', 'calls' => 1], - 'Query End' => ['total_time' => '0.000002', 'calls' => 1], - 'Commit' => ['total_time' => '0.000002', 'calls' => 1], - 'Starting Cleanup' => ['total_time' => '0.000002', 'calls' => 1], - 'Freeing Items' => ['total_time' => '0.000002', 'calls' => 1], - 'Updating Status' => ['total_time' => '0.000007', 'calls' => 1], - 'Reset For Next Command' => ['total_time' => '0.000009', 'calls' => 1], + 'After Opening Tables' => ['total_time' => 0.000006, 'calls' => 2], + 'System Lock' => ['total_time' => 0.000004, 'calls' => 2], + 'Table Lock' => ['total_time' => 0.000015, 'calls' => 2], + 'Unlocking Tables' => ['total_time' => 0.000004, 'calls' => 2], + 'Closing Tables' => ['total_time' => 0.000009, 'calls' => 3], + 'Init' => ['total_time' => 0.000007, 'calls' => 1], + 'Optimizing' => ['total_time' => 0.000004, 'calls' => 1], + 'Statistics' => ['total_time' => 0.000006, 'calls' => 1], + 'Preparing' => ['total_time' => 0.000006, 'calls' => 1], + 'Executing' => ['total_time' => 0.000002, 'calls' => 1], + 'Sending Data' => ['total_time' => 0.000029, 'calls' => 1], + 'End Of Update Loop' => ['total_time' => 0.000003, 'calls' => 1], + 'Query End' => ['total_time' => 0.000002, 'calls' => 1], + 'Commit' => ['total_time' => 0.000002, 'calls' => 1], + 'Starting Cleanup' => ['total_time' => 0.000002, 'calls' => 1], + 'Freeing Items' => ['total_time' => 0.000002, 'calls' => 1], + 'Updating Status' => ['total_time' => 0.000007, 'calls' => 1], + 'Reset For Next Command' => ['total_time' => 0.000009, 'calls' => 1], ], 'chart' => [ - 'Starting' => '0.000017', - 'Checking Permissions' => '0.000003', + 'Starting' => 0.000017, + 'Checking Permissions' => 0.000003, 'Opening Tables' => 0.00016, - 'After Opening Tables' => 6.0E-6, - 'System Lock' => 4.0E-6, - 'Table Lock' => 1.5E-5, - 'Unlocking Tables' => 4.0E-6, - 'Closing Tables' => 9.0E-6, - 'Init' => '0.000007', - 'Optimizing' => '0.000004', - 'Statistics' => '0.000006', - 'Preparing' => '0.000006', - 'Executing' => '0.000002', - 'Sending Data' => '0.000029', - 'End Of Update Loop' => '0.000003', - 'Query End' => '0.000002', - 'Commit' => '0.000002', - 'Starting Cleanup' => '0.000002', - 'Freeing Items' => '0.000002', - 'Updating Status' => '0.000007', - 'Reset For Next Command' => '0.000009', + 'After Opening Tables' => 0.000006, + 'System Lock' => 0.000004, + 'Table Lock' => 0.000015, + 'Unlocking Tables' => 0.000004, + 'Closing Tables' => 0.000009, + 'Init' => 0.000007, + 'Optimizing' => 0.000004, + 'Statistics' => 0.000006, + 'Preparing' => 0.000006, + 'Executing' => 0.000002, + 'Sending Data' => 0.000029, + 'End Of Update Loop' => 0.000003, + 'Query End' => 0.000002, + 'Commit' => 0.000002, + 'Starting Cleanup' => 0.000002, + 'Freeing Items' => 0.000002, + 'Updating Status' => 0.000007, + 'Reset For Next Command' => 0.000009, ], 'profile' => [ ['status' => 'Starting', 'duration' => '17 ยต', 'duration_raw' => '0.000017'],