Merge branch 'QA_5_2'
Signed-off-by: Maurício Meneghini Fauth <mauricio@mfauth.net>
This commit is contained in:
commit
17e34144a1
@ -4560,13 +4560,13 @@ parameters:
|
||||
-
|
||||
message: '#^Cannot access property \$name on PhpMyAdmin\\SqlParser\\Components\\DataType\|null\.$#'
|
||||
identifier: property.nonObject
|
||||
count: 2
|
||||
count: 1
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
message: '#^Cannot access property \$options on PhpMyAdmin\\SqlParser\\Components\\DataType\|null\.$#'
|
||||
identifier: property.nonObject
|
||||
count: 2
|
||||
count: 1
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
@ -4578,7 +4578,7 @@ parameters:
|
||||
-
|
||||
message: '#^Cannot access property \$parameters on PhpMyAdmin\\SqlParser\\Components\\DataType\|null\.$#'
|
||||
identifier: property.nonObject
|
||||
count: 3
|
||||
count: 2
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
@ -4588,9 +4588,9 @@ parameters:
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
message: '#^Cannot call method get\(\) on PhpMyAdmin\\SqlParser\\Components\\OptionsArray\|null\.$#'
|
||||
message: '#^Cannot call method has\(\) on PhpMyAdmin\\SqlParser\\Components\\OptionsArray\|null\.$#'
|
||||
identifier: method.nonObject
|
||||
count: 1
|
||||
count: 2
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
@ -4623,6 +4623,12 @@ parameters:
|
||||
count: 4
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
message: '#^PHPDoc tag @var with type string\|false is not subtype of type bool\.$#'
|
||||
identifier: varTag.type
|
||||
count: 2
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$alias of method PhpMyAdmin\\Types\:\:mapAliasToMysqlType\(\) expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
@ -4899,6 +4905,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Dbal/DatabaseInterface.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$mode of static method PhpMyAdmin\\SqlParser\\Context\:\:setMode\(\) expects int\|string, string\|null given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Dbal/DatabaseInterface.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$path of function basename expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
@ -7161,7 +7173,7 @@ parameters:
|
||||
-
|
||||
message: '#^Cannot access offset mixed on mixed\.$#'
|
||||
identifier: offsetAccess.nonOffsetAccessible
|
||||
count: 1
|
||||
count: 2
|
||||
path: src/Indexes/Index.php
|
||||
|
||||
-
|
||||
@ -12238,11 +12250,17 @@ parameters:
|
||||
path: src/Table/Indexes.php
|
||||
|
||||
-
|
||||
message: '#^Only booleans are allowed in a negated boolean, int\|null given\.$#'
|
||||
message: '#^Only booleans are allowed in a negated boolean, string\|null given\.$#'
|
||||
identifier: booleanNot.exprNotBoolean
|
||||
count: 1
|
||||
path: src/Table/Indexes.php
|
||||
|
||||
-
|
||||
message: '#^Only booleans are allowed in an if condition, int\|null given\.$#'
|
||||
identifier: if.condNotBoolean
|
||||
count: 1
|
||||
path: src/Table/Indexes.php
|
||||
|
||||
-
|
||||
message: '#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\.$#'
|
||||
identifier: foreach.nonIterable
|
||||
|
||||
@ -3381,13 +3381,10 @@
|
||||
<MixedArgumentTypeCoercion>
|
||||
<code><![CDATA[$itemParamDir]]></code>
|
||||
<code><![CDATA[$itemParamName]]></code>
|
||||
<code><![CDATA[$options]]></code>
|
||||
<code><![CDATA[$options]]></code>
|
||||
<code><![CDATA[$retval['item_param_opts_num'][$idx]]]></code>
|
||||
<code><![CDATA[$value]]></code>
|
||||
</MixedArgumentTypeCoercion>
|
||||
<MixedArrayAccess>
|
||||
<code><![CDATA[$opt['value']]]></code>
|
||||
<code><![CDATA[$opt['value']]]></code>
|
||||
<code><![CDATA[$routine['item_param_dir'][$i]]]></code>
|
||||
<code><![CDATA[$routine['item_param_dir'][$i]]]></code>
|
||||
@ -3431,8 +3428,6 @@
|
||||
<code><![CDATA[$itemParamName]]></code>
|
||||
<code><![CDATA[$itemParamType]]></code>
|
||||
<code><![CDATA[$opt]]></code>
|
||||
<code><![CDATA[$opt]]></code>
|
||||
<code><![CDATA[$options[]]]></code>
|
||||
<code><![CDATA[$retval['item_param_opts_num'][$idx][]]]></code>
|
||||
<code><![CDATA[$value]]></code>
|
||||
<code><![CDATA[$value]]></code>
|
||||
@ -3491,11 +3486,9 @@
|
||||
<code><![CDATA[$param->type->parameters]]></code>
|
||||
<code><![CDATA[$routine['SPECIFIC_NAME']]]></code>
|
||||
<code><![CDATA[$routine['SPECIFIC_NAME']]]></code>
|
||||
<code><![CDATA[$stmt->return->parameters]]></code>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullIterator>
|
||||
<code><![CDATA[$param->type->options->options]]></code>
|
||||
<code><![CDATA[$stmt->return->options->options]]></code>
|
||||
</PossiblyNullIterator>
|
||||
<PossiblyNullOperand>
|
||||
<code><![CDATA[$_POST['item_original_type']]]></code>
|
||||
@ -3505,13 +3498,9 @@
|
||||
<code><![CDATA[$param->type->options]]></code>
|
||||
<code><![CDATA[$param->type->options->options]]></code>
|
||||
<code><![CDATA[$param->type->parameters]]></code>
|
||||
<code><![CDATA[$stmt->return->name]]></code>
|
||||
<code><![CDATA[$stmt->return->options]]></code>
|
||||
<code><![CDATA[$stmt->return->options->options]]></code>
|
||||
<code><![CDATA[$stmt->return->parameters]]></code>
|
||||
</PossiblyNullPropertyFetch>
|
||||
<PossiblyNullReference>
|
||||
<code><![CDATA[get]]></code>
|
||||
<code><![CDATA[has]]></code>
|
||||
</PossiblyNullReference>
|
||||
<PossiblyUndefinedArrayOffset>
|
||||
<code><![CDATA[$_POST['item_original_type']]]></code>
|
||||
@ -3633,6 +3622,7 @@
|
||||
</PossiblyInvalidOperand>
|
||||
<PossiblyNullArgument>
|
||||
<code><![CDATA[$_SERVER['SCRIPT_NAME']]]></code>
|
||||
<code><![CDATA[$version['@@sql_mode']]]></code>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullArrayAccess>
|
||||
<code><![CDATA[$resultTarget[]]]></code>
|
||||
@ -5005,9 +4995,11 @@
|
||||
<code><![CDATA[$params['columns']]]></code>
|
||||
</MixedArgument>
|
||||
<MixedArrayOffset>
|
||||
<code><![CDATA[$columns['collations'][$key]]]></code>
|
||||
<code><![CDATA[$columns['sub_parts'][$key]]]></code>
|
||||
</MixedArrayOffset>
|
||||
<MixedAssignment>
|
||||
<code><![CDATA[$collation]]></code>
|
||||
<code><![CDATA[$column]]></code>
|
||||
<code><![CDATA[$key]]></code>
|
||||
<code><![CDATA[$name]]></code>
|
||||
@ -8048,7 +8040,8 @@
|
||||
<code><![CDATA[$column->getSubPart()]]></code>
|
||||
</PossiblyNullOperand>
|
||||
<RiskyTruthyFalsyComparison>
|
||||
<code><![CDATA[! $column->getSubPart()]]></code>
|
||||
<code><![CDATA[! $column->getCollation()]]></code>
|
||||
<code><![CDATA[$column->getSubPart()]]></code>
|
||||
</RiskyTruthyFalsyComparison>
|
||||
</file>
|
||||
<file src="src/Table/Search.php">
|
||||
|
||||
@ -753,7 +753,10 @@ const makeGrid = function (t, enableResize = undefined, enableReorder = undefine
|
||||
|
||||
// remove decimal places if column type not supported
|
||||
if ((decimals === 0) && ($thisField.attr('data-type').indexOf('time') !== -1)) {
|
||||
newHtml = newHtml.substring(0, newHtml.indexOf('.'));
|
||||
var index = newHtml.indexOf('.');
|
||||
if (index !== -1) {
|
||||
newHtml = newHtml.substring(0, index);
|
||||
}
|
||||
}
|
||||
|
||||
// remove additional decimal places
|
||||
|
||||
@ -99,7 +99,7 @@
|
||||
<option value="">{{ t('Charset') }}</option>
|
||||
<option value=""></option>
|
||||
{% for charset in charsets %}
|
||||
<option value="{{ charset.getName() }}" title="{{ charset.getDescription() }}"{{ routine.item_returnopts_text == charset.getName() ? ' selected' }}>{{ charset.getName() }}</option>
|
||||
<option value="{{ charset.getName() }}" title="{{ charset.getDescription() }}"{{ routine.item_returnopts_text|lower == charset.getName() ? ' selected' }}>{{ charset.getName() }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@ -143,6 +143,9 @@
|
||||
<th>
|
||||
{{ t('Size') }}
|
||||
</th>
|
||||
<th>
|
||||
{{ t('Collation') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% set spatial_types = [
|
||||
@ -190,6 +193,13 @@
|
||||
value="{{ index.getChoice() != 'SPATIAL' ?
|
||||
column.getSubPart() }}">
|
||||
</td>
|
||||
<td>
|
||||
<select name="index[columns][collations][]">
|
||||
<option value=""{{ column.Collation ? ' selected' }}>{{ t('None') }}</option>
|
||||
<option value="A"{{ column.Collation == 'A' ? ' selected' }} title="ASC">A</option>
|
||||
<option value="D"{{ column.Collation == 'D' ? ' selected' }} title="DESC">D</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if add_fields > 0 %}
|
||||
@ -223,6 +233,13 @@
|
||||
name="index[columns][sub_parts][]"
|
||||
value="">
|
||||
</td>
|
||||
<td>
|
||||
<select name="index[columns][collations][]">
|
||||
<option value="" selected>{{ t('None') }}</option>
|
||||
<option value="A" title="ASC">A</option>
|
||||
<option value="D" title="DESC">D</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
@ -62,6 +62,17 @@ final class EventsController implements InvocableController
|
||||
if ($request->isAjax()) {
|
||||
if (Current::$message instanceof Message && Current::$message->isSuccess()) {
|
||||
$events = $this->events->getDetails(Current::$database, $_POST['item_name']);
|
||||
if ($events === []) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON(
|
||||
'message',
|
||||
__('The event was dropped immediately after creation.'),
|
||||
);
|
||||
$this->response->addJSON('tableType', 'events');
|
||||
|
||||
return $this->response->response();
|
||||
}
|
||||
|
||||
$event = $events[0];
|
||||
$this->response->addJSON(
|
||||
'name',
|
||||
|
||||
@ -479,19 +479,34 @@ class Routines
|
||||
$retval['item_returnopts_num'] = '';
|
||||
$retval['item_returnopts_text'] = '';
|
||||
|
||||
if (! empty($routine['DTD_IDENTIFIER'])) {
|
||||
$options = [];
|
||||
foreach ($stmt->return->options->options as $opt) {
|
||||
$options[] = is_string($opt) ? $opt : $opt['value'];
|
||||
}
|
||||
|
||||
if (! empty($routine['DTD_IDENTIFIER']) && $stmt->return !== null) {
|
||||
$retval['item_returntype'] = $stmt->return->name;
|
||||
$retval['item_returnlength'] = implode(',', $stmt->return->parameters);
|
||||
$retval['item_returnopts_num'] = implode(' ', $options);
|
||||
$retval['item_returnopts_text'] = implode(' ', $options);
|
||||
|
||||
// Extract charset (CHARSET or CHARACTER SET) separately from numeric options
|
||||
/** @var string|false $charset */
|
||||
$charset = $stmt->return->options->has('CHARSET');
|
||||
if ($charset === false) {
|
||||
/** @var string|false $charset */
|
||||
$charset = $stmt->return->options->has('CHARACTER SET');
|
||||
}
|
||||
|
||||
$retval['item_returnopts_text'] = is_string($charset) ? mb_strtolower($charset) : '';
|
||||
|
||||
// Extract numeric options (UNSIGNED, ZEROFILL, UNSIGNED ZEROFILL.)
|
||||
$numericOpts = [];
|
||||
foreach ($stmt->return->options->options as $opt) {
|
||||
if (! is_string($opt) || ! in_array($opt, $this->numericOptions, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$numericOpts[] = $opt;
|
||||
}
|
||||
|
||||
$retval['item_returnopts_num'] = implode(' ', $numericOpts);
|
||||
}
|
||||
|
||||
$retval['item_definer'] = $stmt->options->get('DEFINER');
|
||||
$retval['item_definer'] = $stmt->options?->has('DEFINER') ?? false;
|
||||
$retval['item_definition'] = $body;
|
||||
$retval['item_isdeterministic'] = '';
|
||||
if ($routine['IS_DETERMINISTIC'] === 'YES') {
|
||||
|
||||
@ -1032,10 +1032,11 @@ class DatabaseInterface
|
||||
*/
|
||||
public function postConnect(Server $currentServer): void
|
||||
{
|
||||
$version = $this->fetchSingleRow('SELECT @@version, @@version_comment');
|
||||
$version = $this->fetchSingleRow('SELECT @@version, @@version_comment, @@sql_mode');
|
||||
|
||||
if ($version !== []) {
|
||||
$this->setVersion($version);
|
||||
Context::setMode($version['@@sql_mode']);
|
||||
}
|
||||
|
||||
$this->query(
|
||||
|
||||
@ -231,9 +231,11 @@ class Index
|
||||
// coming from form
|
||||
// $columns[names][]
|
||||
// $columns[sub_parts][]
|
||||
// $columns[collations][]
|
||||
foreach ($columns['names'] as $key => $name) {
|
||||
$subPart = $columns['sub_parts'][$key] ?? '';
|
||||
$addedColumns[] = ['Column_name' => $name, 'Sub_part' => $subPart];
|
||||
$collation = $columns['collations'][$key] ?? null;
|
||||
$addedColumns[] = ['Column_name' => $name, 'Sub_part' => $subPart, 'Collation' => $collation];
|
||||
}
|
||||
} else {
|
||||
// coming from SHOW INDEXES
|
||||
|
||||
@ -17,7 +17,7 @@ class IndexColumn
|
||||
/** @var int The column sequence number in the index, starting with 1. */
|
||||
private int $seqInIndex = 1;
|
||||
|
||||
/** @var string|null How the column is sorted in the index. "A" (Ascending) or NULL (Not sorted) */
|
||||
/** @var string|null How the column is sorted in the index. "A" (Ascending), "D" (Descending) or NULL (Not sorted) */
|
||||
private string|null $collation = null;
|
||||
|
||||
/**
|
||||
|
||||
@ -98,11 +98,20 @@ final class Indexes
|
||||
$indexFields = [];
|
||||
foreach ($index->getColumns() as $key => $column) {
|
||||
$indexFields[$key] = Util::backquote($column->getName());
|
||||
if (! $column->getSubPart()) {
|
||||
if ($column->getSubPart()) {
|
||||
$indexFields[$key] .= '(' . $column->getSubPart() . ')';
|
||||
}
|
||||
|
||||
if (! $column->getCollation()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$indexFields[$key] .= '(' . $column->getSubPart() . ')';
|
||||
$collation = $column->getCollation();
|
||||
if ($collation === 'A') {
|
||||
$indexFields[$key] .= ' ASC';
|
||||
} elseif ($collation === 'D') {
|
||||
$indexFields[$key] .= ' DESC';
|
||||
}
|
||||
}
|
||||
|
||||
if ($indexFields === []) {
|
||||
|
||||
@ -466,16 +466,25 @@ class Table implements Stringable
|
||||
// if column is virtual, check if server type is Mysql as only Mysql server
|
||||
// supports extra column properties
|
||||
$isVirtualColMysql = $virtuality && Compatibility::isMySqlOrPerconaDb($dbi);
|
||||
// if column is virtual, check if server type is MariaDB as MariaDB server
|
||||
// supports no extra virtual column properties except CHARACTER SET for text column types
|
||||
$isVirtualColMariaDB = $virtuality && Compatibility::isMariaDb($dbi);
|
||||
|
||||
$matches = preg_match('@^(TINYTEXT|TEXT|MEDIUMTEXT|LONGTEXT|VARCHAR|CHAR|ENUM|SET)$@i', $type) === 1;
|
||||
if ($collation !== '' && $collation !== 'NULL' && $matches) {
|
||||
$query .= Util::getCharsetQueryPart(
|
||||
$isVirtualColMariaDB ? (string) preg_replace('~_.+~s', '', $collation) : $collation,
|
||||
true,
|
||||
);
|
||||
// if column is virtual, check if server type is MariaDB as MariaDB server
|
||||
// supports no extra virtual column properties except CHARACTER SET for text column types
|
||||
// https://jira.mariadb.org/browse/MDEV-12161
|
||||
if ($virtuality && Compatibility::isMariaDb($dbi)) {
|
||||
$version = $dbi->getVersion();
|
||||
$isVirtualCollationSupported =
|
||||
$version >= 100509 ||
|
||||
$version >= 100418 && $version < 100500 ||
|
||||
$version >= 100328 && $version < 100400 ||
|
||||
$version >= 100237 && $version < 100300;
|
||||
if (! $isVirtualCollationSupported) {
|
||||
$collation = (string) preg_replace('~_.+~s', '', $collation);
|
||||
}
|
||||
}
|
||||
|
||||
$query .= Util::getCharsetQueryPart($collation, true);
|
||||
}
|
||||
|
||||
if ($virtuality !== '') {
|
||||
|
||||
@ -16,7 +16,6 @@ use PhpMyAdmin\Plugins\Export\ExportSql;
|
||||
use PhpMyAdmin\Plugins\ExportType;
|
||||
use PhpMyAdmin\SqlParser\Components\Expression;
|
||||
use PhpMyAdmin\SqlParser\Components\OptionsArray;
|
||||
use PhpMyAdmin\SqlParser\Context;
|
||||
use PhpMyAdmin\SqlParser\Parser;
|
||||
use PhpMyAdmin\SqlParser\Statements\AlterStatement;
|
||||
use PhpMyAdmin\SqlParser\Statements\CreateStatement;
|
||||
@ -503,11 +502,6 @@ class TableMover
|
||||
*/
|
||||
$destination = new Expression($targetDb, $targetTable, '');
|
||||
|
||||
// Find server's SQL mode so the builder can generate correct
|
||||
// queries.
|
||||
// One of the options that alters the behaviour is `ANSI_QUOTES`.
|
||||
Context::setMode((string) $this->dbi->fetchValue('SELECT @@sql_mode'));
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Phase 1: Dropping existent element of the same name (if exists
|
||||
// and required).
|
||||
|
||||
@ -203,6 +203,8 @@ final class DatabaseInterfaceTest extends AbstractTestCase
|
||||
$versionQueryResult = [
|
||||
'@@version' => '10.20.7-MariaDB-1:10.9.3+maria~ubu2204',
|
||||
'@@version_comment' => 'mariadb.org binary distribution',
|
||||
'@@sql_mode' => 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,'
|
||||
. 'NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION',
|
||||
];
|
||||
LanguageManager::getInstance()->availableLanguages();
|
||||
|
||||
@ -818,6 +820,8 @@ final class DatabaseInterfaceTest extends AbstractTestCase
|
||||
[
|
||||
'@@version' => '6.1.0',
|
||||
'@@version_comment' => "Percona Server (GPL), Release '11', Revision 'c1y2gr1df4a'",
|
||||
'@@sql_mode' => 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,'
|
||||
. 'NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION',
|
||||
],
|
||||
60100,
|
||||
true,
|
||||
@ -828,6 +832,8 @@ final class DatabaseInterfaceTest extends AbstractTestCase
|
||||
[
|
||||
'@@version' => '10.01.40-MariaDB-1:10.01.40+maria~ubu2204',
|
||||
'@@version_comment' => 'mariadb.org binary distribution',
|
||||
'@@sql_mode' => 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,'
|
||||
. 'NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION',
|
||||
],
|
||||
100140,
|
||||
false,
|
||||
@ -835,13 +841,29 @@ final class DatabaseInterfaceTest extends AbstractTestCase
|
||||
false,
|
||||
],
|
||||
[
|
||||
['@@version' => '7.10.3', '@@version_comment' => 'MySQL Community Server (GPL)'],
|
||||
[
|
||||
'@@version' => '7.10.3',
|
||||
'@@version_comment' => 'MySQL Community Server (GPL)',
|
||||
'@@sql_mode' => 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,'
|
||||
. 'NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION',
|
||||
],
|
||||
71003,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[['@@version' => '5.5.0', '@@version_comment' => ''], 50500, true, false, false],
|
||||
[
|
||||
[
|
||||
'@@version' => '5.5.0',
|
||||
'@@version_comment' => '',
|
||||
'@@sql_mode' => 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,'
|
||||
. 'NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION',
|
||||
],
|
||||
50500,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user