| Server IP : 3.96.16.70 / Your IP : 216.73.216.15 Web Server : Apache System : Linux ip-172-31-26-103.ca-central-1.compute.internal 6.1.163-186.299.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Feb 24 16:35:42 UTC 2026 x86_64 User : ec2-user ( 1000) PHP Version : 8.4.18 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/html/prod1.wondermakr.com/phpmyadmin/test/classes/ |
Upload File : |
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Tests;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\ConfigStorage\RelationCleanup;
use PhpMyAdmin\FieldMetadata;
use PhpMyAdmin\Operations;
use PhpMyAdmin\ParseAnalyze;
use PhpMyAdmin\Sql;
use PhpMyAdmin\Template;
use PhpMyAdmin\Transformations;
use ReflectionMethod;
use stdClass;
use const MYSQLI_TYPE_SHORT;
use const MYSQLI_TYPE_TIMESTAMP;
use const MYSQLI_TYPE_VAR_STRING;
/**
* @covers \PhpMyAdmin\Sql
*/
class SqlTest extends AbstractTestCase
{
/** @var Sql */
private $sql;
/**
* Setup for test cases
*/
protected function setUp(): void
{
parent::setUp();
parent::setLanguage();
parent::setTheme();
$GLOBALS['server'] = 1;
$GLOBALS['db'] = 'db';
$GLOBALS['table'] = 'table';
$GLOBALS['cfg']['AllowThirdPartyFraming'] = false;
$GLOBALS['cfg']['SendErrorReports'] = 'ask';
$GLOBALS['cfg']['ServerDefault'] = 1;
$GLOBALS['cfg']['DefaultTabDatabase'] = 'structure';
$GLOBALS['cfg']['DefaultTabTable'] = 'browse';
$GLOBALS['cfg']['ShowDatabasesNavigationAsTree'] = true;
$GLOBALS['cfg']['NavigationTreeDefaultTabTable'] = 'structure';
$GLOBALS['cfg']['NavigationTreeDefaultTabTable2'] = '';
$GLOBALS['cfg']['LimitChars'] = 50;
$GLOBALS['cfg']['Confirm'] = true;
$GLOBALS['cfg']['LoginCookieValidity'] = 1440;
$GLOBALS['cfg']['enable_drag_drop_import'] = true;
$GLOBALS['PMA_PHP_SELF'] = 'index.php';
$relation = new Relation($GLOBALS['dbi']);
$this->sql = new Sql(
$GLOBALS['dbi'],
$relation,
new RelationCleanup($GLOBALS['dbi'], $relation),
new Operations($GLOBALS['dbi'], $relation),
new Transformations(),
new Template()
);
}
/**
* Test for getSqlWithLimitClause
*/
public function testGetSqlWithLimitClause(): void
{
// Test environment.
$GLOBALS['_SESSION']['tmpval']['pos'] = 1;
$GLOBALS['_SESSION']['tmpval']['max_rows'] = 2;
$analyzed_sql_results = $this->parseAndAnalyze('SELECT * FROM test LIMIT 0, 10');
self::assertSame(
'SELECT * FROM test LIMIT 1, 2 ',
$this->callFunction($this->sql, Sql::class, 'getSqlWithLimitClause', [&$analyzed_sql_results])
);
}
/**
* Test for isRememberSortingOrder
*/
public function testIsRememberSortingOrder(): void
{
// Test environment.
$GLOBALS['cfg']['RememberSorting'] = true;
self::assertTrue($this->callFunction($this->sql, Sql::class, 'isRememberSortingOrder', [
$this->parseAndAnalyze('SELECT * FROM tbl'),
]));
self::assertFalse($this->callFunction($this->sql, Sql::class, 'isRememberSortingOrder', [
$this->parseAndAnalyze('SELECT col FROM tbl'),
]));
self::assertFalse($this->callFunction($this->sql, Sql::class, 'isRememberSortingOrder', [
$this->parseAndAnalyze('SELECT 1'),
]));
self::assertFalse($this->callFunction($this->sql, Sql::class, 'isRememberSortingOrder', [
$this->parseAndAnalyze('SELECT col1, col2 FROM tbl'),
]));
self::assertFalse($this->callFunction($this->sql, Sql::class, 'isRememberSortingOrder', [
$this->parseAndAnalyze('SELECT COUNT(*) from tbl'),
]));
}
/**
* Test for isAppendLimitClause
*/
public function testIsAppendLimitClause(): void
{
// Test environment.
$GLOBALS['_SESSION']['tmpval']['max_rows'] = 10;
self::assertTrue($this->callFunction($this->sql, Sql::class, 'isAppendLimitClause', [
$this->parseAndAnalyze('SELECT * FROM tbl'),
]));
self::assertFalse($this->callFunction($this->sql, Sql::class, 'isAppendLimitClause', [
$this->parseAndAnalyze('SELECT * from tbl LIMIT 0, 10'),
]));
}
public function testIsJustBrowsing(): void
{
// Test environment.
$GLOBALS['_SESSION']['tmpval']['max_rows'] = 10;
self::assertTrue(Sql::isJustBrowsing(
$this->parseAndAnalyze('SELECT * FROM db.tbl'),
null
));
self::assertTrue(Sql::isJustBrowsing(
$this->parseAndAnalyze('SELECT * FROM tbl WHERE 1'),
null
));
self::assertFalse(Sql::isJustBrowsing(
$this->parseAndAnalyze('SELECT * from tbl1, tbl2 LIMIT 0, 10'),
null
));
}
/**
* Test for isDeleteTransformationInfo
*/
public function testIsDeleteTransformationInfo(): void
{
self::assertTrue($this->callFunction($this->sql, Sql::class, 'isDeleteTransformationInfo', [
$this->parseAndAnalyze('ALTER TABLE tbl DROP COLUMN col'),
]));
self::assertTrue($this->callFunction($this->sql, Sql::class, 'isDeleteTransformationInfo', [
$this->parseAndAnalyze('DROP TABLE tbl'),
]));
self::assertFalse($this->callFunction($this->sql, Sql::class, 'isDeleteTransformationInfo', [
$this->parseAndAnalyze('SELECT * from tbl'),
]));
}
/**
* Test for hasNoRightsToDropDatabase
*/
public function testHasNoRightsToDropDatabase(): void
{
self::assertTrue($this->sql->hasNoRightsToDropDatabase(
$this->parseAndAnalyze('DROP DATABASE db'),
false,
false
));
self::assertFalse($this->sql->hasNoRightsToDropDatabase(
$this->parseAndAnalyze('DROP TABLE tbl'),
false,
false
));
self::assertFalse($this->sql->hasNoRightsToDropDatabase(
$this->parseAndAnalyze('SELECT * from tbl'),
false,
false
));
}
/**
* Should return false if all columns are not from the same table
*/
public function testWithMultipleTables(): void
{
$col1 = new stdClass();
$col1->table = 'table1';
$col2 = new stdClass();
$col2->table = 'table1';
$col3 = new stdClass();
$col3->table = 'table3';
$fields_meta = [
$col1,
$col2,
$col3,
];
self::assertFalse($this->callFunction($this->sql, Sql::class, 'resultSetHasJustOneTable', [$fields_meta]));
// should not matter on where the odd column occurs
$fields_meta = [
$col2,
$col3,
$col1,
];
self::assertFalse($this->callFunction($this->sql, Sql::class, 'resultSetHasJustOneTable', [$fields_meta]));
$fields_meta = [
$col3,
$col1,
$col2,
];
self::assertFalse($this->callFunction($this->sql, Sql::class, 'resultSetHasJustOneTable', [$fields_meta]));
}
/**
* Should return true if all the columns are from the same table
*/
public function testWithSameTable(): void
{
$col1 = new stdClass();
$col1->table = 'table1';
$col2 = new stdClass();
$col2->table = 'table1';
$col3 = new stdClass();
$col3->table = 'table1';
$fields_meta = [
$col1,
$col2,
$col3,
];
self::assertTrue($this->callFunction($this->sql, Sql::class, 'resultSetHasJustOneTable', [$fields_meta]));
}
/**
* Should return true even if function columns (table is '') occur when others
* are from the same table.
*/
public function testWithFunctionColumns(): void
{
$col1 = new stdClass();
$col1->table = 'table1';
$col2 = new stdClass();
$col2->table = '';
$col3 = new stdClass();
$col3->table = 'table1';
$fields_meta = [
$col1,
$col2,
$col3,
];
self::assertTrue($this->callFunction($this->sql, Sql::class, 'resultSetHasJustOneTable', [$fields_meta]));
// should not matter on where the function column occurs
$fields_meta = [
$col2,
$col3,
$col1,
];
self::assertTrue($this->callFunction($this->sql, Sql::class, 'resultSetHasJustOneTable', [$fields_meta]));
$fields_meta = [
$col3,
$col1,
$col2,
];
self::assertTrue($this->callFunction($this->sql, Sql::class, 'resultSetHasJustOneTable', [$fields_meta]));
}
/**
* We can not say all the columns are from the same table if all the columns
* are function columns (table is '')
*/
public function testWithOnlyFunctionColumns(): void
{
$col1 = new stdClass();
$col1->table = '';
$col2 = new stdClass();
$col2->table = '';
$col3 = new stdClass();
$col3->table = '';
$fields_meta = [
$col1,
$col2,
$col3,
];
self::assertFalse($this->callFunction($this->sql, Sql::class, 'resultSetHasJustOneTable', [$fields_meta]));
}
/**
* @return mixed
*/
private function parseAndAnalyze(string $sqlQuery)
{
global $db;
[$analyzedSqlResults] = ParseAnalyze::sqlQuery($sqlQuery, $db);
return $analyzedSqlResults;
}
public static function dataProviderCountQueryResults(): array
{
// sql query
// session tmpval
// num rows
// result
// just browsing
return [
'join on SELECT results with *' => [
// -- Showing rows 0 - 49 (164056 total, 0 in query, Query took 0.1498 seconds.)
'select * from game_auth_logs l join ('
. ' select al.user_id, max(al.id) as id from game_auth_logs al '
. 'where al.successfull = 1 group by al.user_id ) last_log on last_log.id = l.id;',
['max_rows' => 50, 'pos' => 0],
164056,
50,
false,
'SELECT COUNT(*) FROM (SELECT 1 FROM game_auth_logs AS `l` JOIN ('
. ' select al.user_id, max(al.id) as id from game_auth_logs al '
. 'where al.successfull = 1 group by al.user_id ) AS `last_log` ON last_log.id = l.id'
. ' ) as cnt',
],
'join on SELECT results with alias.*' => [
// -- Showing rows 0 - 24 (267 total, Query took 0.1533 seconds.)
'select l.* from game_auth_logs l join ('
. ' select al.user_id, max(al.id) as id from game_auth_logs al '
. 'where al.successfull = 1 group by al.user_id ) last_log on last_log.id = l.id;',
['max_rows' => 50, 'pos' => 0],
267,
50,
false,
'SELECT COUNT(*) FROM (SELECT 1 FROM game_auth_logs AS `l` JOIN ('
. ' select al.user_id, max(al.id) as id from game_auth_logs al '
. 'where al.successfull = 1 group by al.user_id ) AS `last_log` ON last_log.id = l.id'
. ' ) as cnt',
],
[
'SELECT * FROM company_users WHERE id != 0 LIMIT 0, 10',
['max_rows' => 250],
-1,
-1,
],
[
'SELECT * FROM company_users WHERE id != 0',
[
'max_rows' => 250,
'pos' => -1,
],
-1,
-2,
],
[
'SELECT * FROM company_users WHERE id != 0',
[
'max_rows' => 250,
'pos' => -1,
],
-1,
-2,
],
[
'SELECT * FROM company_users WHERE id != 0',
[
'max_rows' => 250,
'pos' => 250,
],
-1,
249,
],
[
'SELECT * FROM company_users WHERE id != 0',
[
'max_rows' => 250,
'pos' => 4,
],
2,
6,
],
[
'SELECT * FROM company_users WHERE id != 0',
[
'max_rows' => 'all',
'pos' => 4,
],
2,
2,
],
[
null,
[],
2,
0,
],
[
'SELECT * FROM company_users LIMIT 1,4',
[
'max_rows' => 10,
'pos' => 4,
],
20,
20,
],
[
'SELECT * FROM company_users',
[
'max_rows' => 10,
'pos' => 4,
],
20,
4,
],
[
'SELECT * FROM company_users WHERE not_working_count != 0',
[
'max_rows' => 10,
'pos' => 4,
],
20,
0,
],
[
'SELECT * FROM company_users WHERE working_count = 0',
[
'max_rows' => 10,
'pos' => 4,
],
20,
15,
],
[
'UPDATE company_users SET a=1 WHERE working_count = 0',
[
'max_rows' => 10,
'pos' => 4,
],
20,
20,
],
[
'UPDATE company_users SET a=1 WHERE working_count = 0',
[
'max_rows' => 'all',
'pos' => 4,
],
20,
20,
],
[
'UPDATE company_users SET a=1 WHERE working_count = 0',
['max_rows' => 15],
20,
20,
],
[
'SELECT * FROM company_users WHERE id != 0',
[
'max_rows' => 250,
'pos' => 4,
],
2,
6,
true,
],
[
'SELECT *, (SELECT COUNT(*) FROM tbl1) as c1, (SELECT 1 FROM tbl2) as c2 '
. 'FROM company_users WHERE id != 0',
[
'max_rows' => 250,
'pos' => 4,
],
2,
6,
true,
],
[
'SELECT * FROM company_users',
[
'max_rows' => 10,
'pos' => 4,
],
20,
18,
true,
],
[
'SELECT *, 1, (SELECT COUNT(*) FROM tbl1) as c1, '
. '(SELECT 1 FROM tbl2) as c2 FROM company_users WHERE subquery_case = 0',
[
'max_rows' => 10,
'pos' => 4,
],
20,
42,
],
[
'SELECT ( as c2 FROM company_users WHERE working_count = 0',// Invalid query
['max_rows' => 10],
20,
20,
],
[
'SELECT DISTINCT country_id FROM city;',
['max_rows' => 25, 'pos' => 0],
25,
109,
false,
'SELECT COUNT(*) FROM (SELECT DISTINCT country_id FROM city ) as cnt',
],
[
'SELECT * FROM t1 UNION SELECT * FROM t2;',
['max_rows' => -1, 'pos' => 0],
25,
109,
false,
'SELECT COUNT(*) FROM (SELECT * FROM t1 UNION SELECT * FROM t2 ) as cnt',
],
];
}
/**
* @dataProvider dataProviderCountQueryResults
*/
public function testCountQueryResults(
?string $sqlQuery,
array $sessionTmpVal,
int $numRows,
int $expectedNumRows,
bool $justBrowsing = false,
?string $expectedCountQuery = null
): void {
if ($justBrowsing) {
$GLOBALS['cfg']['Server']['DisableIS'] = true;
}
$_SESSION['tmpval'] = $sessionTmpVal;
$analyzed_sql_results = $sqlQuery === null ? [] : $this->parseAndAnalyze($sqlQuery);
if ($expectedCountQuery !== null) {
$this->dummyDbi->addResult(
$expectedCountQuery,
[[$expectedNumRows]],
[],
[]
);
}
$result = $this->callFunction(
$this->sql,
Sql::class,
'countQueryResults',
[
$numRows,
$justBrowsing,
'my_dataset',// db
'company_users',// table
$analyzed_sql_results,
]
);
self::assertSame($expectedNumRows, $result);
$this->assertAllQueriesConsumed();
}
public function testExecuteQueryAndSendQueryResponse(): void
{
$this->dummyDbi->addSelectDb('sakila');
$this->dummyDbi->addResult(
'SELECT * FROM `sakila`.`country` LIMIT 0, 3;',
[
['1', 'Afghanistan', '2006-02-15 04:44:00'],
['2', 'Algeria', '2006-02-15 04:44:00'],
['3', 'American Samoa', '2006-02-15 04:44:00'],
],
['country_id', 'country', 'last_update'],
[
new FieldMetadata(MYSQLI_TYPE_SHORT, 0, (object) ['length' => 5]),
new FieldMetadata(MYSQLI_TYPE_VAR_STRING, 0, (object) ['length' => 200]),
new FieldMetadata(MYSQLI_TYPE_TIMESTAMP, 0, (object) ['length' => 19]),
]
);
$this->dummyDbi->addResult(
'SHOW TABLE STATUS FROM `sakila` WHERE `Name` LIKE \'country%\'',
[
[
'country',
'InnoDB',
'10',
'Dynamic',
'109',
'150',
'16384',
'0',
'0',
'0',
'110',
'2011-12-13 14:15:16',
null,
null,
'utf8mb4_general_ci',
null,
'',
'',
'0',
'N',
],
],
[
'Name',
'Engine',
'Version',
'Row_format',
'Rows',
'Avg_row_length',
'Data_length',
'Max_data_length',
'Index_length',
'Data_free',
'Auto_increment',
'Create_time',
'Update_time',
'Check_time',
'Collation',
'Checksum',
'Create_options',
'Comment',
'Max_index_length',
'Temporary',
]
);
$this->dummyDbi->addResult(
'SHOW CREATE TABLE `sakila`.`country`',
[
[
'country',
'CREATE TABLE `country` (' . "\n"
. ' `country_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,' . "\n"
. ' `country` varchar(50) NOT NULL,' . "\n"
. ' `last_update` timestamp NOT NULL DEFAULT current_timestamp()'
. ' ON UPDATE current_timestamp(),' . "\n"
. ' PRIMARY KEY (`country_id`)' . "\n"
. ') ENGINE=InnoDB AUTO_INCREMENT=110 DEFAULT CHARSET=utf8mb4',
],
],
['Table', 'Create Table']
);
$this->dummyDbi->addResult('SELECT COUNT(*) FROM `sakila`.`country`', [['109']]);
$this->dummyDbi->addResult(
'SHOW FULL COLUMNS FROM `sakila`.`country`',
[
[
'country_id',
'smallint(5) unsigned',
null,
'NO',
'PRI',
null,
'auto_increment',
'select,insert,update,references',
'',
],
[
'country',
'varchar(50)',
'utf8mb4_general_ci',
'NO',
'',
null,
'',
'select,insert,update,references',
'',
],
[
'last_update',
'timestamp',
null,
'NO',
'',
'current_timestamp()',
'on update current_timestamp()',
'select,insert,update,references',
'',
],
],
['Field', 'Type', 'Collation', 'Null', 'Key', 'Default', 'Extra', 'Privileges', 'Comment']
);
$this->dummyDbi->addResult(
'SHOW COLUMNS FROM `sakila`.`country`',
[
['country_id', 'smallint(5) unsigned', 'NO', 'PRI', null, 'auto_increment'],
['country', 'varchar(50)', 'NO', '', null, ''],
['last_update', 'timestamp', 'NO', '', 'current_timestamp()', 'on update current_timestamp()'],
],
['Field', 'Type', 'Null', 'Key', 'Default', 'Extra']
);
$this->dummyDbi->addResult(
'SHOW INDEXES FROM `sakila`.`country`',
[['country', '0', 'PRIMARY', 'country_id']],
['Table', 'Non_unique', 'Key_name', 'Column_name']
);
$this->dummyDbi->addResult(
'SELECT TABLE_NAME FROM information_schema.VIEWS'
. ' WHERE TABLE_SCHEMA = \'sakila\' AND TABLE_NAME = \'country\' AND IS_UPDATABLE = \'YES\'',
[]
);
$_SESSION['sql_from_query_box'] = true;
$GLOBALS['db'] = 'sakila';
$GLOBALS['table'] = 'country';
$GLOBALS['sql_query'] = 'SELECT * FROM `sakila`.`country` LIMIT 0, 3;';
$GLOBALS['cfg']['Server']['DisableIS'] = true;
$GLOBALS['cfg']['Server']['user'] = 'user';
$actual = $this->sql->executeQueryAndSendQueryResponse(
null,
false,
'sakila',
'different_table',
null,
null,
null,
null,
null,
'index.php?route=/sql',
null,
null,
'SELECT * FROM `sakila`.`country` LIMIT 0, 3;',
null
);
self::assertStringContainsString('Showing rows 0 - 2 (3 total', $actual);
self::assertStringContainsString('SELECT * FROM `sakila`.`country` LIMIT 0, 3;', $actual);
self::assertStringContainsString('Afghanistan', $actual);
self::assertStringContainsString('Algeria', $actual);
self::assertStringContainsString('American Samoa', $actual);
self::assertStringContainsString('data-type="int"', $actual);
self::assertStringContainsString('data-type="string"', $actual);
self::assertStringContainsString('data-type="timestamp"', $actual);
}
public function testGetDetailedProfilingStatsWithoutData(): void
{
$method = new ReflectionMethod($this->sql, 'getDetailedProfilingStats');
$method->setAccessible(true);
self::assertSame(
['total_time' => 0, 'states' => [], 'chart' => [], 'profile' => []],
$method->invoke($this->sql, [])
);
}
public function testGetDetailedProfilingStatsWithData(): void
{
$method = new ReflectionMethod($this->sql, 'getDetailedProfilingStats');
$method->setAccessible(true);
$profiling = [
['Status' => 'Starting', 'Duration' => '0.000017'],
['Status' => 'checking permissions', 'Duration' => '0.000003'],
['Status' => 'Opening tables', 'Duration' => '0.000152'],
['Status' => 'After opening tables', 'Duration' => '0.000004'],
['Status' => 'System lock', 'Duration' => '0.000002'],
['Status' => 'table lock', 'Duration' => '0.000003'],
['Status' => 'Opening tables', 'Duration' => '0.000008'],
['Status' => 'After opening tables', 'Duration' => '0.000002'],
['Status' => 'System lock', 'Duration' => '0.000002'],
['Status' => 'table lock', 'Duration' => '0.000012'],
['Status' => 'Unlocking tables', 'Duration' => '0.000003'],
['Status' => 'closing tables', 'Duration' => '0.000005'],
['Status' => 'init', 'Duration' => '0.000007'],
['Status' => 'Optimizing', 'Duration' => '0.000004'],
['Status' => 'Statistics', 'Duration' => '0.000006'],
['Status' => 'Preparing', 'Duration' => '0.000006'],
['Status' => 'Executing', 'Duration' => '0.000002'],
['Status' => 'Sending data', 'Duration' => '0.000029'],
['Status' => 'End of update loop', 'Duration' => '0.000003'],
['Status' => 'Query end', 'Duration' => '0.000002'],
['Status' => 'Commit', 'Duration' => '0.000002'],
['Status' => 'closing tables', 'Duration' => '0.000002'],
['Status' => 'Unlocking tables', 'Duration' => '0.000001'],
['Status' => 'closing tables', 'Duration' => '0.000002'],
['Status' => 'Starting cleanup', 'Duration' => '0.000002'],
['Status' => 'Freeing items', 'Duration' => '0.000002'],
['Status' => 'Updating status', 'Duration' => '0.000007'],
['Status' => 'Reset for next command', 'Duration' => '0.000009'],
];
$expected = [
'total_time' => 0.000299,
'states' => [
'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],
],
'chart' => [
'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',
],
'profile' => [
['status' => 'Starting', 'duration' => '17 µ', 'duration_raw' => '0.000017'],
['status' => 'Checking Permissions', 'duration' => '3 µ', 'duration_raw' => '0.000003'],
['status' => 'Opening Tables', 'duration' => '152 µ', 'duration_raw' => '0.000152'],
['status' => 'After Opening Tables', 'duration' => '4 µ', 'duration_raw' => '0.000004'],
['status' => 'System Lock', 'duration' => '2 µ', 'duration_raw' => '0.000002'],
['status' => 'Table Lock', 'duration' => '3 µ', 'duration_raw' => '0.000003'],
['status' => 'Opening Tables', 'duration' => '8 µ', 'duration_raw' => '0.000008'],
['status' => 'After Opening Tables', 'duration' => '2 µ', 'duration_raw' => '0.000002'],
['status' => 'System Lock', 'duration' => '2 µ', 'duration_raw' => '0.000002'],
['status' => 'Table Lock', 'duration' => '12 µ', 'duration_raw' => '0.000012'],
['status' => 'Unlocking Tables', 'duration' => '3 µ', 'duration_raw' => '0.000003'],
['status' => 'Closing Tables', 'duration' => '5 µ', 'duration_raw' => '0.000005'],
['status' => 'Init', 'duration' => '7 µ', 'duration_raw' => '0.000007'],
['status' => 'Optimizing', 'duration' => '4 µ', 'duration_raw' => '0.000004'],
['status' => 'Statistics', 'duration' => '6 µ', 'duration_raw' => '0.000006'],
['status' => 'Preparing', 'duration' => '6 µ', 'duration_raw' => '0.000006'],
['status' => 'Executing', 'duration' => '2 µ', 'duration_raw' => '0.000002'],
['status' => 'Sending Data', 'duration' => '29 µ', 'duration_raw' => '0.000029'],
['status' => 'End Of Update Loop', 'duration' => '3 µ', 'duration_raw' => '0.000003'],
['status' => 'Query End', 'duration' => '2 µ', 'duration_raw' => '0.000002'],
['status' => 'Commit', 'duration' => '2 µ', 'duration_raw' => '0.000002'],
['status' => 'Closing Tables', 'duration' => '2 µ', 'duration_raw' => '0.000002'],
['status' => 'Unlocking Tables', 'duration' => '1 µ', 'duration_raw' => '0.000001'],
['status' => 'Closing Tables', 'duration' => '2 µ', 'duration_raw' => '0.000002'],
['status' => 'Starting Cleanup', 'duration' => '2 µ', 'duration_raw' => '0.000002'],
['status' => 'Freeing Items', 'duration' => '2 µ', 'duration_raw' => '0.000002'],
['status' => 'Updating Status', 'duration' => '7 µ', 'duration_raw' => '0.000007'],
['status' => 'Reset For Next Command', 'duration' => '9 µ', 'duration_raw' => '0.000009'],
],
];
self::assertSame($expected, $method->invoke($this->sql, $profiling));
}
}