From 3c88ec1457922cdec386264ffd72bb4202ccf651 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Wed, 30 Apr 2025 21:17:16 +0100 Subject: [PATCH] Refactor getFunctionNames & getProcedureNames Signed-off-by: Kamil Tekiela --- src/Database/Routines.php | 38 +++-------------- src/Operations.php | 5 ++- src/Plugins/Export/ExportSql.php | 5 ++- src/Plugins/Export/ExportXml.php | 5 ++- tests/unit/Database/RoutinesTest.php | 47 +++++++++------------ tests/unit/Plugins/Export/ExportXmlTest.php | 19 +++++++-- tests/unit/Stubs/DbiDummy.php | 12 +++--- 7 files changed, 58 insertions(+), 73 deletions(-) diff --git a/src/Database/Routines.php b/src/Database/Routines.php index d24caa7050..79adc82509 100644 --- a/src/Database/Routines.php +++ b/src/Database/Routines.php @@ -1258,38 +1258,14 @@ class Routines * @return array * @psalm-return list */ - public static function getFunctionNames(DatabaseInterface $dbi, string $db): array + public static function getNames(DatabaseInterface $dbi, string $db, RoutineType $type): array { - /** @psalm-var list $functions */ - $functions = $dbi->fetchResultSimple('SHOW FUNCTION STATUS;'); - $names = []; - foreach ($functions as $function) { - if ($function['Db'] !== $db || $function['Type'] !== 'FUNCTION' || $function['Name'] === '') { - continue; - } - - $names[] = $function['Name']; - } - - return $names; - } - - /** - * @return array - * @psalm-return list - */ - public static function getProcedureNames(DatabaseInterface $dbi, string $db): array - { - /** @psalm-var list $procedures */ - $procedures = $dbi->fetchResultSimple('SHOW PROCEDURE STATUS;'); - $names = []; - foreach ($procedures as $procedure) { - if ($procedure['Db'] !== $db || $procedure['Type'] !== 'PROCEDURE' || $procedure['Name'] === '') { - continue; - } - - $names[] = $procedure['Name']; - } + /** @var list $names */ + $names = $dbi->fetchSingleColumn( + 'SELECT SPECIFIC_NAME FROM information_schema.ROUTINES' + . ' WHERE ROUTINE_SCHEMA = ' . $dbi->quoteString($db) + . " AND ROUTINE_TYPE = '" . $type->value . "' AND SPECIFIC_NAME != ''", + ); return $names; } diff --git a/src/Operations.php b/src/Operations.php index 8199b30f90..f456c4b9a4 100644 --- a/src/Operations.php +++ b/src/Operations.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Database\Events; use PhpMyAdmin\Database\Routines; +use PhpMyAdmin\Database\RoutineType; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Engines\Innodb; use PhpMyAdmin\Identifiers\DatabaseName; @@ -55,7 +56,7 @@ class Operations */ public function runProcedureAndFunctionDefinitions(string $db, DatabaseName $newDatabaseName): void { - foreach (Routines::getProcedureNames($this->dbi, $db) as $procedureName) { + foreach (Routines::getNames($this->dbi, $db, RoutineType::Procedure) as $procedureName) { $this->dbi->selectDb($db); $query = Routines::getProcedureDefinition($this->dbi, $db, $procedureName); if ($query === null) { @@ -68,7 +69,7 @@ class Operations $this->dbi->query($query); } - foreach (Routines::getFunctionNames($this->dbi, $db) as $functionName) { + foreach (Routines::getNames($this->dbi, $db, RoutineType::Function) as $functionName) { $this->dbi->selectDb($db); $query = Routines::getFunctionDefinition($this->dbi, $db, $functionName); if ($query === null) { diff --git a/src/Plugins/Export/ExportSql.php b/src/Plugins/Export/ExportSql.php index d7db94927a..f5fa3dc5c1 100644 --- a/src/Plugins/Export/ExportSql.php +++ b/src/Plugins/Export/ExportSql.php @@ -13,6 +13,7 @@ use PhpMyAdmin\Config; use PhpMyAdmin\Current; use PhpMyAdmin\Database\Events; use PhpMyAdmin\Database\Routines; +use PhpMyAdmin\Database\RoutineType; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Exceptions\ExportException; @@ -617,8 +618,8 @@ class ExportSql extends ExportPlugin $delimiter = '$$'; $dbi = DatabaseInterface::getInstance(); - $procedureNames = Routines::getProcedureNames($dbi, $db); - $functionNames = Routines::getFunctionNames($dbi, $db); + $procedureNames = Routines::getNames($dbi, $db, RoutineType::Procedure); + $functionNames = Routines::getNames($dbi, $db, RoutineType::Function); if ($procedureNames || $functionNames) { $text .= "\n" diff --git a/src/Plugins/Export/ExportXml.php b/src/Plugins/Export/ExportXml.php index 814dce0728..8411a6e5d7 100644 --- a/src/Plugins/Export/ExportXml.php +++ b/src/Plugins/Export/ExportXml.php @@ -9,6 +9,7 @@ use PhpMyAdmin\Config; use PhpMyAdmin\Current; use PhpMyAdmin\Database\Events; use PhpMyAdmin\Database\Routines; +use PhpMyAdmin\Database\RoutineType; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; @@ -307,7 +308,7 @@ class ExportXml extends ExportPlugin $head .= $this->exportDefinitions( Current::$database, 'function', - Routines::getFunctionNames($dbi, Current::$database), + Routines::getNames($dbi, Current::$database, RoutineType::Function), ); } @@ -315,7 +316,7 @@ class ExportXml extends ExportPlugin $head .= $this->exportDefinitions( Current::$database, 'procedure', - Routines::getProcedureNames($dbi, Current::$database), + Routines::getNames($dbi, Current::$database, RoutineType::Procedure), ); } diff --git a/tests/unit/Database/RoutinesTest.php b/tests/unit/Database/RoutinesTest.php index 10094f666f..0c6cc22def 100644 --- a/tests/unit/Database/RoutinesTest.php +++ b/tests/unit/Database/RoutinesTest.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Tests\Database; use PhpMyAdmin\Config; use PhpMyAdmin\Current; use PhpMyAdmin\Database\Routines; +use PhpMyAdmin\Database\RoutineType; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Tests\AbstractTestCase; @@ -476,18 +477,16 @@ class RoutinesTest extends AbstractTestCase { $dbiDummy = $this->createDbiDummy(); $dbiDummy->addResult( - 'SHOW FUNCTION STATUS;', + 'SELECT SPECIFIC_NAME FROM information_schema.ROUTINES ' + . "WHERE ROUTINE_SCHEMA = 'test_db' AND ROUTINE_TYPE = 'FUNCTION' AND SPECIFIC_NAME != ''", [ - ['db_test', 'test_func', 'FUNCTION'], - ['test_db', 'test_func1', 'FUNCTION'], - ['test_db', '', 'FUNCTION'], - ['test_db', 'test_func2', 'FUNCTION'], - ['test_db', 'test_func', 'PROCEDURE'], + ['test_func1'], + ['test_func2'], ], - ['Db', 'Name', 'Type'], + ['Name'], ); - $names = Routines::getFunctionNames($this->createDatabaseInterface($dbiDummy), 'test_db'); + $names = Routines::getNames($this->createDatabaseInterface($dbiDummy), 'test_db', RoutineType::Function); self::assertSame(['test_func1', 'test_func2'], $names); $dbiDummy->assertAllQueriesConsumed(); @@ -497,12 +496,13 @@ class RoutinesTest extends AbstractTestCase { $dbiDummy = $this->createDbiDummy(); $dbiDummy->addResult( - 'SHOW FUNCTION STATUS;', - [['db_test', 'test_func', 'FUNCTION'], ['test_db', '', 'FUNCTION'], ['test_db', 'test_func', 'PROCEDURE']], + 'SELECT SPECIFIC_NAME FROM information_schema.ROUTINES ' + . "WHERE ROUTINE_SCHEMA = 'test_db' AND ROUTINE_TYPE = 'FUNCTION' AND SPECIFIC_NAME != ''", + [], ['Db', 'Name', 'Type'], ); - $names = Routines::getFunctionNames($this->createDatabaseInterface($dbiDummy), 'test_db'); + $names = Routines::getNames($this->createDatabaseInterface($dbiDummy), 'test_db', RoutineType::Function); self::assertSame([], $names); $dbiDummy->assertAllQueriesConsumed(); @@ -512,18 +512,16 @@ class RoutinesTest extends AbstractTestCase { $dbiDummy = $this->createDbiDummy(); $dbiDummy->addResult( - 'SHOW PROCEDURE STATUS;', + 'SELECT SPECIFIC_NAME FROM information_schema.ROUTINES ' + . "WHERE ROUTINE_SCHEMA = 'test_db' AND ROUTINE_TYPE = 'PROCEDURE' AND SPECIFIC_NAME != ''", [ - ['db_test', 'test_proc', 'PROCEDURE'], - ['test_db', 'test_proc1', 'PROCEDURE'], - ['test_db', '', 'PROCEDURE'], - ['test_db', 'test_proc2', 'PROCEDURE'], - ['test_db', 'test_proc', 'FUNCTION'], + ['test_proc1', 'PROCEDURE'], + ['test_proc2', 'PROCEDURE'], ], - ['Db', 'Name', 'Type'], + ['Name'], ); - $names = Routines::getProcedureNames($this->createDatabaseInterface($dbiDummy), 'test_db'); + $names = Routines::getNames($this->createDatabaseInterface($dbiDummy), 'test_db', RoutineType::Procedure); self::assertSame(['test_proc1', 'test_proc2'], $names); $dbiDummy->assertAllQueriesConsumed(); @@ -533,16 +531,13 @@ class RoutinesTest extends AbstractTestCase { $dbiDummy = $this->createDbiDummy(); $dbiDummy->addResult( - 'SHOW PROCEDURE STATUS;', - [ - ['db_test', 'test_proc', 'PROCEDURE'], - ['test_db', '', 'PROCEDURE'], - ['test_db', 'test_proc', 'FUNCTION'], - ], + 'SELECT SPECIFIC_NAME FROM information_schema.ROUTINES ' + . "WHERE ROUTINE_SCHEMA = 'test_db' AND ROUTINE_TYPE = 'PROCEDURE' AND SPECIFIC_NAME != ''", + [], ['Db', 'Name', 'Type'], ); - $names = Routines::getProcedureNames($this->createDatabaseInterface($dbiDummy), 'test_db'); + $names = Routines::getNames($this->createDatabaseInterface($dbiDummy), 'test_db', RoutineType::Procedure); self::assertSame([], $names); $dbiDummy->assertAllQueriesConsumed(); diff --git a/tests/unit/Plugins/Export/ExportXmlTest.php b/tests/unit/Plugins/Export/ExportXmlTest.php index 2fcebe2cee..da7ac09aa6 100644 --- a/tests/unit/Plugins/Export/ExportXmlTest.php +++ b/tests/unit/Plugins/Export/ExportXmlTest.php @@ -179,8 +179,8 @@ class ExportXmlTest extends AbstractTestCase $config->selectedServer['DisableIS'] = false; Current::$database = 'd<"b'; - $functions = [['d<"b', 'fn', 'FUNCTION']]; - $procedures = [['d<"b', 'pr', 'PROCEDURE']]; + $functions = [['fn']]; + $procedures = [['pr']]; $dbiDummy = $this->createDbiDummy(); $dbi = $this->createDatabaseInterface($dbiDummy); @@ -191,8 +191,18 @@ class ExportXmlTest extends AbstractTestCase [['utf-8', 'utf8_general_ci']], ['DEFAULT_CHARACTER_SET_NAME', 'DEFAULT_COLLATION_NAME'], ); - $dbiDummy->addResult('SHOW FUNCTION STATUS;', $functions, ['Db', 'Name', 'Type']); - $dbiDummy->addResult('SHOW PROCEDURE STATUS;', $procedures, ['Db', 'Name', 'Type']); + $dbiDummy->addResult( + 'SELECT SPECIFIC_NAME FROM information_schema.ROUTINES ' + . "WHERE ROUTINE_SCHEMA = 'd<\\\"b' AND ROUTINE_TYPE = 'FUNCTION' AND SPECIFIC_NAME != ''", + $functions, + ['Name'], + ); + $dbiDummy->addResult( + 'SELECT SPECIFIC_NAME FROM information_schema.ROUTINES ' + . "WHERE ROUTINE_SCHEMA = 'd<\\\"b' AND ROUTINE_TYPE = 'PROCEDURE' AND SPECIFIC_NAME != ''", + $procedures, + ['Name'], + ); $dbiDummy->addResult('SHOW CREATE TABLE `d<"b`.`table`', [['table', '"tbl"']]); $dbiDummy->addResult( 'SELECT 1 FROM information_schema.VIEWS WHERE TABLE_SCHEMA = \'d<\"b\' AND TABLE_NAME = \'table\'', @@ -327,6 +337,7 @@ class ExportXmlTest extends AbstractTestCase ' </pma:structure_schemas>', $result, ); + $dbiDummy->assertAllQueriesConsumed(); } public function testExportFooter(): void diff --git a/tests/unit/Stubs/DbiDummy.php b/tests/unit/Stubs/DbiDummy.php index c75f01523f..15ff21fc0a 100644 --- a/tests/unit/Stubs/DbiDummy.php +++ b/tests/unit/Stubs/DbiDummy.php @@ -1780,14 +1780,14 @@ class DbiDummy implements DbiExtension ], ], [ - 'query' => 'SHOW PROCEDURE STATUS;', - 'columns' => ['Db', 'Name', 'Type'], - 'result' => [['test_db', 'test_proc1', 'PROCEDURE'], ['test_db', 'test_proc2', 'PROCEDURE']], + 'query' => "SELECT SPECIFIC_NAME FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = 'test_db' AND ROUTINE_TYPE = 'PROCEDURE' AND SPECIFIC_NAME != ''", + 'columns' => ['Name'], + 'result' => [['test_proc1'], ['test_proc2']], ], [ - 'query' => 'SHOW FUNCTION STATUS;', - 'columns' => ['Db', 'Name', 'Type'], - 'result' => [['test_db', 'test_func', 'FUNCTION']], + 'query' => "SELECT SPECIFIC_NAME FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = 'test_db' AND ROUTINE_TYPE = 'FUNCTION' AND SPECIFIC_NAME != ''", + 'columns' => ['Name'], + 'result' => [['test_func']], ], [ 'query' => 'SHOW CREATE PROCEDURE `test_db`.`test_proc1`',