Move getDbInfo()
Signed-off-by: Kamil Tekiela <tekiela246@gmail.com>
This commit is contained in:
parent
b63c9735ca
commit
7e57731a92
@ -1989,12 +1989,36 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Binary operation "\." between bool\|float\|int\|string and array\<string\>\|string\|false results in an error\.$#'
|
||||
identifier: binaryOp.invalid
|
||||
count: 1
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Binary operation "\." between non\-empty\-string and array\<string\>\|string\|false results in an error\.$#'
|
||||
identifier: binaryOp.invalid
|
||||
count: 1
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Call to function array_search\(\) requires parameter \#3 to be set\.$#'
|
||||
identifier: function.strict
|
||||
count: 4
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Cannot access offset ''table_limit_offset'' on mixed\.$#'
|
||||
identifier: offsetAccess.nonOffsetAccessible
|
||||
count: 4
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Cannot access offset ''table_limit_offset_db'' on mixed\.$#'
|
||||
identifier: offsetAccess.nonOffsetAccessible
|
||||
count: 2
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Loose comparison via "\!\=" is not allowed\.$#'
|
||||
identifier: notEqual.notAllowed
|
||||
@ -2007,6 +2031,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Method PhpMyAdmin\\Controllers\\Database\\StructureController\:\:getTableListPosition\(\) should return int but returns mixed\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Method PhpMyAdmin\\Controllers\\Database\\StructureController\:\:getValuesForAriaTable\(\) should return array\{array\<int\|string\|null\>, string, string, string, string, float\|int, int\} but returns array\{array\<int\|string\|null\>, string, string, string, string, mixed, int\}\.$#'
|
||||
identifier: return.type
|
||||
@ -2043,6 +2073,12 @@ parameters:
|
||||
count: 3
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$str of method PhpMyAdmin\\Dbal\\DatabaseInterface\:\:escapeMysqlWildcards\(\) expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$str of method PhpMyAdmin\\Dbal\\DatabaseInterface\:\:quoteString\(\) expects string, int\|string\|null given\.$#'
|
||||
identifier: argument.type
|
||||
@ -2085,6 +2121,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$table of method PhpMyAdmin\\Dbal\\DatabaseInterface\:\:getTablesFull\(\) expects array\<mixed\>\|string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Controllers/Database/StructureController.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$tableName of method PhpMyAdmin\\Dbal\\DatabaseInterface\:\:getTable\(\) expects string, int\|string\|null given\.$#'
|
||||
identifier: argument.type
|
||||
@ -14100,18 +14142,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/UserPrivilegesFactory.php
|
||||
|
||||
-
|
||||
message: '#^Binary operation "\." between bool\|float\|int\|string and array\<string\>\|string\|false results in an error\.$#'
|
||||
identifier: binaryOp.invalid
|
||||
count: 1
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
message: '#^Binary operation "\." between non\-empty\-string and array\<string\>\|string\|false results in an error\.$#'
|
||||
identifier: binaryOp.invalid
|
||||
count: 1
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
message: '#^Call to deprecated function strftime\(\)\.$#'
|
||||
identifier: function.deprecated
|
||||
@ -14124,7 +14154,7 @@ parameters:
|
||||
Use dependency injection instead\.$#
|
||||
'''
|
||||
identifier: staticMethod.deprecated
|
||||
count: 8
|
||||
count: 6
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
@ -14133,19 +14163,7 @@ parameters:
|
||||
Use dependency injection instead\.$#
|
||||
'''
|
||||
identifier: staticMethod.deprecated
|
||||
count: 9
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
message: '#^Cannot access offset ''table_limit_offset'' on mixed\.$#'
|
||||
identifier: offsetAccess.nonOffsetAccessible
|
||||
count: 4
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
message: '#^Cannot access offset ''table_limit_offset_db'' on mixed\.$#'
|
||||
identifier: offsetAccess.nonOffsetAccessible
|
||||
count: 2
|
||||
count: 7
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
@ -14166,12 +14184,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
message: '#^Method PhpMyAdmin\\Util\:\:getTableListPosition\(\) should return int but returns mixed\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
message: '#^Only booleans are allowed in a negated boolean, int\<0, 2\> given\.$#'
|
||||
identifier: booleanNot.exprNotBoolean
|
||||
@ -14214,24 +14226,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$str of method PhpMyAdmin\\Dbal\\DatabaseInterface\:\:escapeMysqlWildcards\(\) expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$array of function array_key_exists expects array, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$table of method PhpMyAdmin\\Dbal\\DatabaseInterface\:\:getTablesFull\(\) expects array\<mixed\>\|string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Util.php
|
||||
|
||||
-
|
||||
message: '#^Variable static method call on PhpMyAdmin\\Util\.$#'
|
||||
identifier: staticMethod.dynamicName
|
||||
@ -15447,7 +15447,7 @@ parameters:
|
||||
Use dependency injection instead\.$#
|
||||
'''
|
||||
identifier: staticMethod.deprecated
|
||||
count: 6
|
||||
count: 9
|
||||
path: tests/unit/Controllers/Database/StructureControllerTest.php
|
||||
|
||||
-
|
||||
@ -15456,7 +15456,7 @@ parameters:
|
||||
Use dependency injection instead\.$#
|
||||
'''
|
||||
identifier: staticMethod.deprecated
|
||||
count: 5
|
||||
count: 7
|
||||
path: tests/unit/Controllers/Database/StructureControllerTest.php
|
||||
|
||||
-
|
||||
@ -18105,7 +18105,7 @@ parameters:
|
||||
Use dependency injection instead\.$#
|
||||
'''
|
||||
identifier: staticMethod.deprecated
|
||||
count: 7
|
||||
count: 6
|
||||
path: tests/unit/UtilTest.php
|
||||
|
||||
-
|
||||
|
||||
@ -1168,6 +1168,17 @@
|
||||
<code><![CDATA[$replicaInfo['Wild_Do_Table']]]></code>
|
||||
<code><![CDATA[$replicaInfo['Wild_Ignore_Table']]]></code>
|
||||
</MixedArgument>
|
||||
<MixedArgumentTypeCoercion>
|
||||
<code><![CDATA[uksort($tables, strnatcasecmp(...))]]></code>
|
||||
</MixedArgumentTypeCoercion>
|
||||
<MixedArrayAccess>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset']]]></code>
|
||||
</MixedArrayAccess>
|
||||
<MixedArrayAssignment>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset']]]></code>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset']]]></code>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset_db']]]></code>
|
||||
</MixedArrayAssignment>
|
||||
<MixedAssignment>
|
||||
<code><![CDATA[$charset]]></code>
|
||||
<code><![CDATA[$dbTable]]></code>
|
||||
@ -1179,11 +1190,17 @@
|
||||
<MixedMethodCall>
|
||||
<code><![CDATA[getCharset]]></code>
|
||||
</MixedMethodCall>
|
||||
<MixedReturnStatement>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset']]]></code>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset']]]></code>
|
||||
</MixedReturnStatement>
|
||||
<MoreSpecificReturnType>
|
||||
<code><![CDATA[list{(string|int|null)[], string, string, string, string, int, bool, int}]]></code>
|
||||
</MoreSpecificReturnType>
|
||||
<PossiblyFalseOperand>
|
||||
<code><![CDATA[$columnNames]]></code>
|
||||
<code><![CDATA[$this->config->settings['NavigationTreeTableSeparator']]]></code>
|
||||
<code><![CDATA[$this->config->settings['NavigationTreeTableSeparator']]]></code>
|
||||
</PossiblyFalseOperand>
|
||||
<PossiblyInvalidArgument>
|
||||
<code><![CDATA[$currentTable['Collation']]]></code>
|
||||
@ -1208,6 +1225,8 @@
|
||||
<code><![CDATA[$currentTable['Index_length']]]></code>
|
||||
<code><![CDATA[$currentTable['Index_length']]]></code>
|
||||
<code><![CDATA[$currentTable['Index_length']]]></code>
|
||||
<code><![CDATA[$this->config->settings['NavigationTreeTableSeparator']]]></code>
|
||||
<code><![CDATA[$this->config->settings['NavigationTreeTableSeparator']]]></code>
|
||||
</PossiblyInvalidOperand>
|
||||
<PossiblyNullArgument>
|
||||
<code><![CDATA[$currentTable['TABLE_NAME']]]></code>
|
||||
@ -1223,6 +1242,10 @@
|
||||
<code><![CDATA[$currentTable['TABLE_NAME']]]></code>
|
||||
<code><![CDATA[$currentTable['TABLE_ROWS']]]></code>
|
||||
</PossiblyNullOperand>
|
||||
<RedundantCast>
|
||||
<code><![CDATA[(string) $_REQUEST['tbl_group']]]></code>
|
||||
<code><![CDATA[(string) $_REQUEST['tbl_group']]]></code>
|
||||
</RedundantCast>
|
||||
<RiskyTruthyFalsyComparison>
|
||||
<code><![CDATA[! $currentTable['COUNTED']]]></code>
|
||||
</RiskyTruthyFalsyComparison>
|
||||
@ -8903,10 +8926,6 @@
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
@ -8920,16 +8939,7 @@
|
||||
</MixedArgument>
|
||||
<MixedArgumentTypeCoercion>
|
||||
<code><![CDATA[$columnNames]]></code>
|
||||
<code><![CDATA[uksort($tables, strnatcasecmp(...))]]></code>
|
||||
</MixedArgumentTypeCoercion>
|
||||
<MixedArrayAccess>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset']]]></code>
|
||||
</MixedArrayAccess>
|
||||
<MixedArrayAssignment>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset']]]></code>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset']]]></code>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset_db']]]></code>
|
||||
</MixedArrayAssignment>
|
||||
<MixedAssignment>
|
||||
<code><![CDATA[$array]]></code>
|
||||
<code><![CDATA[$columnNames[]]]></code>
|
||||
@ -8938,27 +8948,13 @@
|
||||
<MixedOperand>
|
||||
<code><![CDATA[$value]]></code>
|
||||
</MixedOperand>
|
||||
<MixedReturnStatement>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset']]]></code>
|
||||
<code><![CDATA[$_SESSION['tmpval']['table_limit_offset']]]></code>
|
||||
</MixedReturnStatement>
|
||||
<PossiblyFalseOperand>
|
||||
<code><![CDATA[$config->settings['NavigationTreeTableSeparator']]]></code>
|
||||
<code><![CDATA[$config->settings['NavigationTreeTableSeparator']]]></code>
|
||||
<code><![CDATA[mb_strpos($value, '.')]]></code>
|
||||
<code><![CDATA[mb_strrpos($columnSpecification, ')')]]></code>
|
||||
</PossiblyFalseOperand>
|
||||
<PossiblyInvalidOperand>
|
||||
<code><![CDATA[$config->settings['NavigationTreeTableSeparator']]]></code>
|
||||
<code><![CDATA[$config->settings['NavigationTreeTableSeparator']]]></code>
|
||||
</PossiblyInvalidOperand>
|
||||
<PossiblyNullArgument>
|
||||
<code><![CDATA[$value]]></code>
|
||||
</PossiblyNullArgument>
|
||||
<RedundantCast>
|
||||
<code><![CDATA[(string) $_REQUEST['tbl_group']]]></code>
|
||||
<code><![CDATA[(string) $_REQUEST['tbl_group']]]></code>
|
||||
</RedundantCast>
|
||||
<RiskyTruthyFalsyComparison>
|
||||
<code><![CDATA[$firstBracketPos]]></code>
|
||||
<code><![CDATA[$schemaPrivileges]]></code>
|
||||
@ -9653,6 +9649,11 @@
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
|
||||
@ -11424,7 +11425,6 @@
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
</DeprecatedMethod>
|
||||
<InvalidPropertyAssignmentValue>
|
||||
<code><![CDATA[Config::getInstance()->selectedServer]]></code>
|
||||
|
||||
@ -43,6 +43,8 @@ use function ceil;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function is_numeric;
|
||||
use function is_scalar;
|
||||
use function is_string;
|
||||
use function max;
|
||||
use function mb_substr;
|
||||
@ -50,6 +52,8 @@ use function md5;
|
||||
use function preg_match;
|
||||
use function preg_quote;
|
||||
use function sprintf;
|
||||
use function strnatcasecmp;
|
||||
use function uksort;
|
||||
|
||||
/**
|
||||
* Handles database structure logic
|
||||
@ -96,11 +100,11 @@ final class StructureController implements InvocableController
|
||||
*/
|
||||
private function getDatabaseInfo(ServerRequest $request): void
|
||||
{
|
||||
[$tables, $totalNumTables] = Util::getDbInfo($request, Current::$database);
|
||||
[$tables, $totalNumTables] = $this->getDbInfo($request, Current::$database);
|
||||
|
||||
$this->tables = $tables;
|
||||
$this->numTables = count($tables);
|
||||
$this->position = Util::getTableListPosition($request, Current::$database);
|
||||
$this->position = $this->getTableListPosition($request, Current::$database);
|
||||
$this->totalNumTables = $totalNumTables;
|
||||
|
||||
/**
|
||||
@ -912,4 +916,222 @@ final class StructureController implements InvocableController
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of tables in the current db and information about these tables if possible.
|
||||
*
|
||||
* @return array{(string|int|null)[][], int}
|
||||
*/
|
||||
public function getDbInfo(ServerRequest $request, string $db, bool $isResultLimited = true): array
|
||||
{
|
||||
/**
|
||||
* information about tables in db
|
||||
*/
|
||||
$tables = [];
|
||||
|
||||
// Special speedup for newer MySQL Versions (in 4.0 format changed)
|
||||
if ($this->config->settings['SkipLockedTables'] === true) {
|
||||
$tables = $this->getTablesWhenOpen($db);
|
||||
}
|
||||
|
||||
$totalNumTables = null;
|
||||
if ($tables === []) {
|
||||
// Set some sorting defaults
|
||||
$sort = 'Name';
|
||||
$sortOrder = 'ASC';
|
||||
|
||||
/** @var mixed $sortParam */
|
||||
$sortParam = $request->getParam('sort');
|
||||
if (is_string($sortParam)) {
|
||||
$sortableNameMappings = [
|
||||
'table' => 'Name',
|
||||
'records' => 'Rows',
|
||||
'type' => 'Engine',
|
||||
'collation' => 'Collation',
|
||||
'size' => 'Data_length',
|
||||
'overhead' => 'Data_free',
|
||||
'creation' => 'Create_time',
|
||||
'last_update' => 'Update_time',
|
||||
'last_check' => 'Check_time',
|
||||
'comment' => 'Comment',
|
||||
];
|
||||
|
||||
// Make sure the sort type is implemented
|
||||
if (isset($sortableNameMappings[$sortParam])) {
|
||||
$sort = $sortableNameMappings[$sortParam];
|
||||
if ($request->getParam('sort_order') === 'DESC') {
|
||||
$sortOrder = 'DESC';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$groupWithSeparator = false;
|
||||
$tableType = null;
|
||||
$limitOffset = 0;
|
||||
$limitCount = false;
|
||||
$groupTable = [];
|
||||
|
||||
/** @var mixed $tableGroupParam */
|
||||
$tableGroupParam = $request->getParam('tbl_group');
|
||||
/** @var mixed $tableTypeParam */
|
||||
$tableTypeParam = $request->getParam('tbl_type');
|
||||
if (
|
||||
is_string($tableGroupParam) && $tableGroupParam !== ''
|
||||
|| is_string($tableTypeParam) && $tableTypeParam !== ''
|
||||
) {
|
||||
if (is_string($tableTypeParam) && $tableTypeParam !== '') {
|
||||
// only tables for selected type
|
||||
$tableType = $tableTypeParam;
|
||||
}
|
||||
|
||||
if (is_string($tableGroupParam) && $tableGroupParam !== '') {
|
||||
// only tables for selected group
|
||||
// include the table with the exact name of the group if such exists
|
||||
$groupTable = $this->dbi->getTablesFull(
|
||||
$db,
|
||||
$tableGroupParam,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
$sort,
|
||||
$sortOrder,
|
||||
$tableType,
|
||||
);
|
||||
$groupWithSeparator = $tableGroupParam . $this->config->settings['NavigationTreeTableSeparator'];
|
||||
}
|
||||
} else {
|
||||
// all tables in db
|
||||
// - get the total number of tables
|
||||
// (needed for proper working of the MaxTableList feature)
|
||||
$tables = $this->dbi->getTables($db);
|
||||
$totalNumTables = count($tables);
|
||||
if ($isResultLimited) {
|
||||
// fetch the details for a possible limited subset
|
||||
$limitOffset = $this->getTableListPosition($request, $db);
|
||||
$limitCount = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We must use union operator here instead of array_merge to preserve numerical keys
|
||||
$tables = $groupTable + $this->dbi->getTablesFull(
|
||||
$db,
|
||||
$groupWithSeparator !== false ? $groupWithSeparator : $tables,
|
||||
$groupWithSeparator !== false,
|
||||
$limitOffset,
|
||||
$limitCount,
|
||||
$sort,
|
||||
$sortOrder,
|
||||
$tableType,
|
||||
);
|
||||
}
|
||||
|
||||
return [
|
||||
$tables,
|
||||
$totalNumTables ?? count($tables), // needed for proper working of the MaxTableList feature
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of tables in the current db, taking into account
|
||||
* that they might be "in use"
|
||||
*
|
||||
* @return (string|int|null)[][] list of tables
|
||||
*/
|
||||
private function getTablesWhenOpen(string $db): array
|
||||
{
|
||||
$openTables = $this->dbi->query(
|
||||
'SHOW OPEN TABLES FROM ' . Util::backquote($db) . ' WHERE In_use > 0;',
|
||||
);
|
||||
|
||||
// Blending out tables in use
|
||||
$openTableNames = [];
|
||||
|
||||
/** @var string $tableName */
|
||||
foreach ($openTables as ['Table' => $tableName]) {
|
||||
$openTableNames[] = $tableName;
|
||||
}
|
||||
|
||||
// is there at least one "in use" table?
|
||||
if ($openTableNames === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$tables = [];
|
||||
$tblGroupSql = '';
|
||||
$whereAdded = false;
|
||||
if (
|
||||
isset($_REQUEST['tbl_group'])
|
||||
&& is_scalar($_REQUEST['tbl_group'])
|
||||
&& (string) $_REQUEST['tbl_group'] !== ''
|
||||
) {
|
||||
$group = $this->dbi->escapeMysqlWildcards((string) $_REQUEST['tbl_group']);
|
||||
$groupWithSeparator = $this->dbi->escapeMysqlWildcards(
|
||||
$_REQUEST['tbl_group'] . $this->config->settings['NavigationTreeTableSeparator'],
|
||||
);
|
||||
$tblGroupSql .= ' WHERE ('
|
||||
. Util::backquote('Tables_in_' . $db)
|
||||
. ' LIKE ' . $this->dbi->quoteString($groupWithSeparator . '%')
|
||||
. ' OR '
|
||||
. Util::backquote('Tables_in_' . $db)
|
||||
. ' LIKE ' . $this->dbi->quoteString($group) . ')';
|
||||
$whereAdded = true;
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['tbl_type']) && in_array($_REQUEST['tbl_type'], ['table', 'view'], true)) {
|
||||
$tblGroupSql .= $whereAdded ? ' AND' : ' WHERE';
|
||||
if ($_REQUEST['tbl_type'] === 'view') {
|
||||
$tblGroupSql .= " `Table_type` NOT IN ('BASE TABLE', 'SYSTEM VERSIONED')";
|
||||
} else {
|
||||
$tblGroupSql .= " `Table_type` IN ('BASE TABLE', 'SYSTEM VERSIONED')";
|
||||
}
|
||||
}
|
||||
|
||||
$dbInfoResult = $this->dbi->query('SHOW FULL TABLES FROM ' . Util::backquote($db) . $tblGroupSql);
|
||||
|
||||
if ($dbInfoResult->numRows() > 0) {
|
||||
$names = [];
|
||||
while ($tableName = $dbInfoResult->fetchValue()) {
|
||||
if (! in_array($tableName, $openTableNames, true)) {
|
||||
$names[] = $tableName;
|
||||
} else { // table in use
|
||||
$tables[$tableName] = [
|
||||
'TABLE_NAME' => $tableName,
|
||||
'ENGINE' => '',
|
||||
'TABLE_TYPE' => '',
|
||||
'TABLE_ROWS' => 0,
|
||||
'TABLE_COMMENT' => '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($names !== []) {
|
||||
$tables += $this->dbi->getTablesFull($db, $names);
|
||||
}
|
||||
|
||||
if ($this->config->settings['NaturalOrder']) {
|
||||
uksort($tables, strnatcasecmp(...));
|
||||
}
|
||||
}
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
public function getTableListPosition(ServerRequest $request, string $db): int
|
||||
{
|
||||
if (
|
||||
! isset($_SESSION['tmpval']['table_limit_offset'])
|
||||
|| $_SESSION['tmpval']['table_limit_offset_db'] !== $db
|
||||
) {
|
||||
$_SESSION['tmpval']['table_limit_offset'] = 0;
|
||||
$_SESSION['tmpval']['table_limit_offset_db'] = $db;
|
||||
}
|
||||
|
||||
/** @var string|null $posParam */
|
||||
$posParam = $request->getParam('pos');
|
||||
if (is_numeric($posParam)) {
|
||||
$_SESSION['tmpval']['table_limit_offset'] = (int) $posParam;
|
||||
}
|
||||
|
||||
return $_SESSION['tmpval']['table_limit_offset'];
|
||||
}
|
||||
}
|
||||
|
||||
227
src/Util.php
227
src/Util.php
@ -8,7 +8,6 @@ use DateTimeImmutable;
|
||||
use PhpMyAdmin\ConfigStorage\UserGroupLevel;
|
||||
use PhpMyAdmin\Dbal\DatabaseInterface;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\Query\Compatibility;
|
||||
use PhpMyAdmin\SqlParser\Context;
|
||||
use PhpMyAdmin\SqlParser\Token;
|
||||
@ -42,7 +41,6 @@ use function implode;
|
||||
use function in_array;
|
||||
use function ini_get;
|
||||
use function is_array;
|
||||
use function is_numeric;
|
||||
use function is_object;
|
||||
use function is_scalar;
|
||||
use function is_string;
|
||||
@ -77,13 +75,11 @@ use function str_replace;
|
||||
use function str_starts_with;
|
||||
use function strftime;
|
||||
use function strlen;
|
||||
use function strnatcasecmp;
|
||||
use function strrev;
|
||||
use function strtolower;
|
||||
use function strtr;
|
||||
use function substr;
|
||||
use function trim;
|
||||
use function uksort;
|
||||
|
||||
use const ENT_COMPAT;
|
||||
use const ENT_QUOTES;
|
||||
@ -1483,210 +1479,6 @@ class Util
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of tables in the current db and information about these tables if possible.
|
||||
*
|
||||
* @return array{(string|int|null)[][], int}
|
||||
*/
|
||||
public static function getDbInfo(ServerRequest $request, string $db, bool $isResultLimited = true): array
|
||||
{
|
||||
/**
|
||||
* information about tables in db
|
||||
*/
|
||||
$tables = [];
|
||||
|
||||
$dbi = DatabaseInterface::getInstance();
|
||||
$config = Config::getInstance();
|
||||
// Special speedup for newer MySQL Versions (in 4.0 format changed)
|
||||
if ($config->settings['SkipLockedTables'] === true) {
|
||||
$tables = self::getTablesWhenOpen($db);
|
||||
}
|
||||
|
||||
$totalNumTables = null;
|
||||
if ($tables === []) {
|
||||
// Set some sorting defaults
|
||||
$sort = 'Name';
|
||||
$sortOrder = 'ASC';
|
||||
|
||||
/** @var mixed $sortParam */
|
||||
$sortParam = $request->getParam('sort');
|
||||
if (is_string($sortParam)) {
|
||||
$sortableNameMappings = [
|
||||
'table' => 'Name',
|
||||
'records' => 'Rows',
|
||||
'type' => 'Engine',
|
||||
'collation' => 'Collation',
|
||||
'size' => 'Data_length',
|
||||
'overhead' => 'Data_free',
|
||||
'creation' => 'Create_time',
|
||||
'last_update' => 'Update_time',
|
||||
'last_check' => 'Check_time',
|
||||
'comment' => 'Comment',
|
||||
];
|
||||
|
||||
// Make sure the sort type is implemented
|
||||
if (isset($sortableNameMappings[$sortParam])) {
|
||||
$sort = $sortableNameMappings[$sortParam];
|
||||
if ($request->getParam('sort_order') === 'DESC') {
|
||||
$sortOrder = 'DESC';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$groupWithSeparator = false;
|
||||
$tableType = null;
|
||||
$limitOffset = 0;
|
||||
$limitCount = false;
|
||||
$groupTable = [];
|
||||
|
||||
/** @var mixed $tableGroupParam */
|
||||
$tableGroupParam = $request->getParam('tbl_group');
|
||||
/** @var mixed $tableTypeParam */
|
||||
$tableTypeParam = $request->getParam('tbl_type');
|
||||
if (
|
||||
is_string($tableGroupParam) && $tableGroupParam !== ''
|
||||
|| is_string($tableTypeParam) && $tableTypeParam !== ''
|
||||
) {
|
||||
if (is_string($tableTypeParam) && $tableTypeParam !== '') {
|
||||
// only tables for selected type
|
||||
$tableType = $tableTypeParam;
|
||||
}
|
||||
|
||||
if (is_string($tableGroupParam) && $tableGroupParam !== '') {
|
||||
// only tables for selected group
|
||||
// include the table with the exact name of the group if such exists
|
||||
$groupTable = $dbi->getTablesFull(
|
||||
$db,
|
||||
$tableGroupParam,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
$sort,
|
||||
$sortOrder,
|
||||
$tableType,
|
||||
);
|
||||
$groupWithSeparator = $tableGroupParam . $config->settings['NavigationTreeTableSeparator'];
|
||||
}
|
||||
} else {
|
||||
// all tables in db
|
||||
// - get the total number of tables
|
||||
// (needed for proper working of the MaxTableList feature)
|
||||
$tables = $dbi->getTables($db);
|
||||
$totalNumTables = count($tables);
|
||||
if ($isResultLimited) {
|
||||
// fetch the details for a possible limited subset
|
||||
$limitOffset = self::getTableListPosition($request, $db);
|
||||
$limitCount = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We must use union operator here instead of array_merge to preserve numerical keys
|
||||
$tables = $groupTable + $dbi->getTablesFull(
|
||||
$db,
|
||||
$groupWithSeparator !== false ? $groupWithSeparator : $tables,
|
||||
$groupWithSeparator !== false,
|
||||
$limitOffset,
|
||||
$limitCount,
|
||||
$sort,
|
||||
$sortOrder,
|
||||
$tableType,
|
||||
);
|
||||
}
|
||||
|
||||
return [
|
||||
$tables,
|
||||
$totalNumTables ?? count($tables), // needed for proper working of the MaxTableList feature
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of tables in the current db, taking into account
|
||||
* that they might be "in use"
|
||||
*
|
||||
* @return (string|int|null)[][] list of tables
|
||||
*/
|
||||
private static function getTablesWhenOpen(string $db): array
|
||||
{
|
||||
$dbi = DatabaseInterface::getInstance();
|
||||
|
||||
$openTables = $dbi->query(
|
||||
'SHOW OPEN TABLES FROM ' . self::backquote($db) . ' WHERE In_use > 0;',
|
||||
);
|
||||
|
||||
// Blending out tables in use
|
||||
$openTableNames = [];
|
||||
|
||||
/** @var string $tableName */
|
||||
foreach ($openTables as ['Table' => $tableName]) {
|
||||
$openTableNames[] = $tableName;
|
||||
}
|
||||
|
||||
// is there at least one "in use" table?
|
||||
if ($openTableNames === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$tables = [];
|
||||
$tblGroupSql = '';
|
||||
$whereAdded = false;
|
||||
$config = Config::getInstance();
|
||||
if (
|
||||
isset($_REQUEST['tbl_group'])
|
||||
&& is_scalar($_REQUEST['tbl_group'])
|
||||
&& (string) $_REQUEST['tbl_group'] !== ''
|
||||
) {
|
||||
$group = $dbi->escapeMysqlWildcards((string) $_REQUEST['tbl_group']);
|
||||
$groupWithSeparator = $dbi->escapeMysqlWildcards(
|
||||
$_REQUEST['tbl_group'] . $config->settings['NavigationTreeTableSeparator'],
|
||||
);
|
||||
$tblGroupSql .= ' WHERE ('
|
||||
. self::backquote('Tables_in_' . $db)
|
||||
. ' LIKE ' . $dbi->quoteString($groupWithSeparator . '%')
|
||||
. ' OR '
|
||||
. self::backquote('Tables_in_' . $db)
|
||||
. ' LIKE ' . $dbi->quoteString($group) . ')';
|
||||
$whereAdded = true;
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['tbl_type']) && in_array($_REQUEST['tbl_type'], ['table', 'view'], true)) {
|
||||
$tblGroupSql .= $whereAdded ? ' AND' : ' WHERE';
|
||||
if ($_REQUEST['tbl_type'] === 'view') {
|
||||
$tblGroupSql .= " `Table_type` NOT IN ('BASE TABLE', 'SYSTEM VERSIONED')";
|
||||
} else {
|
||||
$tblGroupSql .= " `Table_type` IN ('BASE TABLE', 'SYSTEM VERSIONED')";
|
||||
}
|
||||
}
|
||||
|
||||
$dbInfoResult = $dbi->query('SHOW FULL TABLES FROM ' . self::backquote($db) . $tblGroupSql);
|
||||
|
||||
if ($dbInfoResult->numRows() > 0) {
|
||||
$names = [];
|
||||
while ($tableName = $dbInfoResult->fetchValue()) {
|
||||
if (! in_array($tableName, $openTableNames, true)) {
|
||||
$names[] = $tableName;
|
||||
} else { // table in use
|
||||
$tables[$tableName] = [
|
||||
'TABLE_NAME' => $tableName,
|
||||
'ENGINE' => '',
|
||||
'TABLE_TYPE' => '',
|
||||
'TABLE_ROWS' => 0,
|
||||
'TABLE_COMMENT' => '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($names !== []) {
|
||||
$tables += $dbi->getTablesFull($db, $names);
|
||||
}
|
||||
|
||||
if ($config->settings['NaturalOrder']) {
|
||||
uksort($tables, strnatcasecmp(...));
|
||||
}
|
||||
}
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of used PHP extensions.
|
||||
*
|
||||
@ -1929,25 +1721,6 @@ class Util
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function getTableListPosition(ServerRequest $request, string $db): int
|
||||
{
|
||||
if (
|
||||
! isset($_SESSION['tmpval']['table_limit_offset'])
|
||||
|| $_SESSION['tmpval']['table_limit_offset_db'] !== $db
|
||||
) {
|
||||
$_SESSION['tmpval']['table_limit_offset'] = 0;
|
||||
$_SESSION['tmpval']['table_limit_offset_db'] = $db;
|
||||
}
|
||||
|
||||
/** @var string|null $posParam */
|
||||
$posParam = $request->getParam('pos');
|
||||
if (is_numeric($posParam)) {
|
||||
$_SESSION['tmpval']['table_limit_offset'] = (int) $posParam;
|
||||
}
|
||||
|
||||
return $_SESSION['tmpval']['table_limit_offset'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum upload size as limited by PHP
|
||||
* Used with permission from Moodle (https://moodle.org/) by Martin Dougiamas
|
||||
|
||||
@ -19,6 +19,7 @@ use PhpMyAdmin\Tests\AbstractTestCase;
|
||||
use PhpMyAdmin\Tests\Stubs\ResponseRenderer as ResponseStub;
|
||||
use PhpMyAdmin\Tracking\TrackingChecker;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
|
||||
@ -379,4 +380,105 @@ class StructureControllerTest extends AbstractTestCase
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetDbInfo(): void
|
||||
{
|
||||
Config::getInstance()->selectedServer['DisableIS'] = true;
|
||||
|
||||
$dbiDummy = $this->createDbiDummy();
|
||||
$dbiDummy->addResult('SHOW TABLES FROM `test_db`;', [['test_table']], ['Tables_in_test_db']);
|
||||
DatabaseInterface::$instance = $this->createDatabaseInterface($dbiDummy);
|
||||
|
||||
$dbi = DatabaseInterface::getInstance();
|
||||
$structureController = new StructureController(
|
||||
$this->response,
|
||||
$this->template,
|
||||
$this->relation,
|
||||
$this->replication,
|
||||
$dbi,
|
||||
self::createStub(TrackingChecker::class),
|
||||
self::createStub(PageSettings::class),
|
||||
new DbTableExists($dbi),
|
||||
Config::getInstance(),
|
||||
);
|
||||
|
||||
$tableInfo = [
|
||||
'Name' => 'test_table',
|
||||
'Engine' => 'InnoDB',
|
||||
'Version' => '10',
|
||||
'Row_format' => 'Dynamic',
|
||||
'Rows' => '3',
|
||||
'Avg_row_length' => '5461',
|
||||
'Data_length' => '16384',
|
||||
'Max_data_length' => '0',
|
||||
'Index_length' => '0',
|
||||
'Data_free' => '0',
|
||||
'Auto_increment' => '4',
|
||||
'Create_time' => '2011-12-13 14:15:16',
|
||||
'Update_time' => null,
|
||||
'Check_time' => null,
|
||||
'Collation' => 'utf8mb4_general_ci',
|
||||
'Checksum' => null,
|
||||
'Create_options' => '',
|
||||
'Comment' => '',
|
||||
'Max_index_length' => '0',
|
||||
'Temporary' => 'N',
|
||||
'Type' => 'InnoDB',
|
||||
'TABLE_SCHEMA' => 'test_db',
|
||||
'TABLE_NAME' => 'test_table',
|
||||
'ENGINE' => 'InnoDB',
|
||||
'VERSION' => '10',
|
||||
'ROW_FORMAT' => 'Dynamic',
|
||||
'TABLE_ROWS' => '3',
|
||||
'AVG_ROW_LENGTH' => '5461',
|
||||
'DATA_LENGTH' => '16384',
|
||||
'MAX_DATA_LENGTH' => '0',
|
||||
'INDEX_LENGTH' => '0',
|
||||
'DATA_FREE' => '0',
|
||||
'AUTO_INCREMENT' => '4',
|
||||
'CREATE_TIME' => '2011-12-13 14:15:16',
|
||||
'UPDATE_TIME' => null,
|
||||
'CHECK_TIME' => null,
|
||||
'TABLE_COLLATION' => 'utf8mb4_general_ci',
|
||||
'CHECKSUM' => null,
|
||||
'CREATE_OPTIONS' => '',
|
||||
'TABLE_COMMENT' => '',
|
||||
'TABLE_TYPE' => 'BASE TABLE',
|
||||
];
|
||||
$expected = [['test_table' => $tableInfo], 1];
|
||||
$actual = $structureController->getDbInfo(self::createStub(ServerRequest::class), 'test_db');
|
||||
self::assertSame($expected, $actual);
|
||||
}
|
||||
|
||||
public function testGetTableListPosition(): void
|
||||
{
|
||||
$dbi = DatabaseInterface::getInstance();
|
||||
$structureController = new StructureController(
|
||||
$this->response,
|
||||
$this->template,
|
||||
$this->relation,
|
||||
$this->replication,
|
||||
$dbi,
|
||||
self::createStub(TrackingChecker::class),
|
||||
self::createStub(PageSettings::class),
|
||||
new DbTableExists($dbi),
|
||||
Config::getInstance(),
|
||||
);
|
||||
|
||||
// Default 0
|
||||
$actual = $structureController->getTableListPosition(self::createStub(ServerRequest::class), 'test_db');
|
||||
self::assertSame(0, $actual);
|
||||
|
||||
// From POST
|
||||
$requestStub = self::createStub(ServerRequestInterface::class);
|
||||
$requestStub->method('getQueryParams')->willReturn([]);
|
||||
$requestStub->method('getParsedBody')->willReturn(['pos' => '250']);
|
||||
$request = new ServerRequest($requestStub);
|
||||
$actual = $structureController->getTableListPosition($request, 'test_db');
|
||||
self::assertSame(250, $actual);
|
||||
|
||||
// From SESSION
|
||||
$actual = $structureController->getTableListPosition(self::createStub(ServerRequest::class), 'test_db');
|
||||
self::assertSame(250, $actual);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@ use DateTimeImmutable;
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Current;
|
||||
use PhpMyAdmin\Dbal\DatabaseInterface;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\MoTranslator\Loader;
|
||||
use PhpMyAdmin\SqlParser\Context;
|
||||
use PhpMyAdmin\SqlParser\Token;
|
||||
@ -18,7 +17,6 @@ use PhpMyAdmin\Version;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
use function __;
|
||||
use function _setlocale;
|
||||
@ -1325,81 +1323,6 @@ SQL;
|
||||
self::assertSame(['route=/table/structure', 'db=sakila', 'table=address'], $actual);
|
||||
}
|
||||
|
||||
public function testGetDbInfo(): void
|
||||
{
|
||||
Config::getInstance()->selectedServer['DisableIS'] = true;
|
||||
|
||||
$dbiDummy = $this->createDbiDummy();
|
||||
$dbiDummy->addResult('SHOW TABLES FROM `test_db`;', [['test_table']], ['Tables_in_test_db']);
|
||||
DatabaseInterface::$instance = $this->createDatabaseInterface($dbiDummy);
|
||||
|
||||
$tableInfo = [
|
||||
'Name' => 'test_table',
|
||||
'Engine' => 'InnoDB',
|
||||
'Version' => '10',
|
||||
'Row_format' => 'Dynamic',
|
||||
'Rows' => '3',
|
||||
'Avg_row_length' => '5461',
|
||||
'Data_length' => '16384',
|
||||
'Max_data_length' => '0',
|
||||
'Index_length' => '0',
|
||||
'Data_free' => '0',
|
||||
'Auto_increment' => '4',
|
||||
'Create_time' => '2011-12-13 14:15:16',
|
||||
'Update_time' => null,
|
||||
'Check_time' => null,
|
||||
'Collation' => 'utf8mb4_general_ci',
|
||||
'Checksum' => null,
|
||||
'Create_options' => '',
|
||||
'Comment' => '',
|
||||
'Max_index_length' => '0',
|
||||
'Temporary' => 'N',
|
||||
'Type' => 'InnoDB',
|
||||
'TABLE_SCHEMA' => 'test_db',
|
||||
'TABLE_NAME' => 'test_table',
|
||||
'ENGINE' => 'InnoDB',
|
||||
'VERSION' => '10',
|
||||
'ROW_FORMAT' => 'Dynamic',
|
||||
'TABLE_ROWS' => '3',
|
||||
'AVG_ROW_LENGTH' => '5461',
|
||||
'DATA_LENGTH' => '16384',
|
||||
'MAX_DATA_LENGTH' => '0',
|
||||
'INDEX_LENGTH' => '0',
|
||||
'DATA_FREE' => '0',
|
||||
'AUTO_INCREMENT' => '4',
|
||||
'CREATE_TIME' => '2011-12-13 14:15:16',
|
||||
'UPDATE_TIME' => null,
|
||||
'CHECK_TIME' => null,
|
||||
'TABLE_COLLATION' => 'utf8mb4_general_ci',
|
||||
'CHECKSUM' => null,
|
||||
'CREATE_OPTIONS' => '',
|
||||
'TABLE_COMMENT' => '',
|
||||
'TABLE_TYPE' => 'BASE TABLE',
|
||||
];
|
||||
$expected = [['test_table' => $tableInfo], 1];
|
||||
$actual = Util::getDbInfo(self::createStub(ServerRequest::class), 'test_db');
|
||||
self::assertSame($expected, $actual);
|
||||
}
|
||||
|
||||
public function testGetTableListPosition(): void
|
||||
{
|
||||
// Default 0
|
||||
$actual = Util::getTableListPosition(self::createStub(ServerRequest::class), 'test_db');
|
||||
self::assertSame(0, $actual);
|
||||
|
||||
// From POST
|
||||
$requestStub = self::createStub(ServerRequestInterface::class);
|
||||
$requestStub->method('getQueryParams')->willReturn([]);
|
||||
$requestStub->method('getParsedBody')->willReturn(['pos' => '250']);
|
||||
$request = new ServerRequest($requestStub);
|
||||
$actual = Util::getTableListPosition($request, 'test_db');
|
||||
self::assertSame(250, $actual);
|
||||
|
||||
// From SESSION
|
||||
$actual = Util::getTableListPosition(self::createStub(ServerRequest::class), 'test_db');
|
||||
self::assertSame(250, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for Util::testIsUUIDSupported() method.
|
||||
*
|
||||
|
||||
Loading…
Reference in New Issue
Block a user