Merge pull request #19698 from kamil-tekiela/Routines-enum
Introduce enum RoutineType
This commit is contained in:
commit
fd4e7bc80b
@ -2028,6 +2028,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controllers/Database/RoutinesController.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Database\\RoutineType\:\:tryFrom\(\) expects int\|string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Controllers/Database/RoutinesController.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$type of method PhpMyAdmin\\Database\\Routines\:\:getDataFromName\(\) expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
@ -2046,12 +2052,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controllers/Database/RoutinesController.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#3 \$which of static method PhpMyAdmin\\Database\\Routines\:\:getDetails\(\) expects string\|null, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Controllers/Database/RoutinesController.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#4 \$name of static method PhpMyAdmin\\Database\\Routines\:\:getDetails\(\) expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
@ -5193,12 +5193,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
message: '#^Binary operation "\.\=" between non\-falsy\-string and mixed results in an error\.$#'
|
||||
identifier: assignOp.invalid
|
||||
count: 1
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
message: '''
|
||||
#^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Config\:
|
||||
@ -5259,7 +5253,7 @@ parameters:
|
||||
-
|
||||
message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#'
|
||||
identifier: empty.notAllowed
|
||||
count: 21
|
||||
count: 13
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
@ -5292,12 +5286,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$haystack of function str_contains expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$haystack of function stripos expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
@ -5307,7 +5295,7 @@ parameters:
|
||||
-
|
||||
message: '#^Parameter \#1 \$identifier of static method PhpMyAdmin\\Util\:\:backquote\(\) expects string\|Stringable\|null, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 9
|
||||
count: 8
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
@ -5325,7 +5313,7 @@ parameters:
|
||||
-
|
||||
message: '#^Parameter \#1 \$str of method PhpMyAdmin\\Dbal\\DatabaseInterface\:\:quoteString\(\) expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 7
|
||||
count: 6
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
@ -5337,7 +5325,7 @@ parameters:
|
||||
-
|
||||
message: '#^Parameter \#1 \$string of function htmlspecialchars expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 2
|
||||
count: 1
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
@ -5370,12 +5358,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$string of function explode expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$subject of function preg_match expects string, mixed given\.$#'
|
||||
identifier: argument.type
|
||||
@ -5413,7 +5395,7 @@ parameters:
|
||||
path: src/Database/Routines.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#7 \$itemType of method PhpMyAdmin\\Database\\Routines\:\:processParamsAndBuild\(\) expects string, mixed given\.$#'
|
||||
message: '#^Parameter \#7 \$itemType of method PhpMyAdmin\\Database\\Routines\:\:processParamsAndBuild\(\) expects PhpMyAdmin\\Database\\RoutineType, PhpMyAdmin\\Database\\RoutineType\|null given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Database/Routines.php
|
||||
|
||||
@ -973,8 +973,8 @@
|
||||
<code><![CDATA[$_POST['item_name']]]></code>
|
||||
<code><![CDATA[$_POST['item_name']]]></code>
|
||||
<code><![CDATA[$_POST['item_type']]]></code>
|
||||
<code><![CDATA[$_POST['item_type']]]></code>
|
||||
<code><![CDATA[$_REQUEST['item_name']]]></code>
|
||||
<code><![CDATA[$_REQUEST['type'] ?? '']]></code>
|
||||
</PossiblyInvalidArgument>
|
||||
<PossiblyInvalidCast>
|
||||
<code><![CDATA[$_GET['item_name']]]></code>
|
||||
@ -3468,10 +3468,6 @@
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
<code><![CDATA[Config::getInstance()]]></code>
|
||||
</DeprecatedMethod>
|
||||
<InvalidArgument>
|
||||
<code><![CDATA[$itemParamDir]]></code>
|
||||
<code><![CDATA[$itemParamName]]></code>
|
||||
</InvalidArgument>
|
||||
<InvalidArrayOffset>
|
||||
<code><![CDATA[$retval['item_param_dir'][$key]]]></code>
|
||||
</InvalidArrayOffset>
|
||||
@ -3500,6 +3496,8 @@
|
||||
<code><![CDATA[$value]]></code>
|
||||
</MixedArgument>
|
||||
<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>
|
||||
@ -3546,6 +3544,9 @@
|
||||
</MixedArrayOffset>
|
||||
<MixedAssignment>
|
||||
<code><![CDATA[$i]]></code>
|
||||
<code><![CDATA[$itemParamLength]]></code>
|
||||
<code><![CDATA[$itemParamName]]></code>
|
||||
<code><![CDATA[$itemParamType]]></code>
|
||||
<code><![CDATA[$opt]]></code>
|
||||
<code><![CDATA[$opt]]></code>
|
||||
<code><![CDATA[$options[]]]></code>
|
||||
@ -3565,7 +3566,6 @@
|
||||
</MixedReturnTypeCoercion>
|
||||
<PossiblyInvalidArgument>
|
||||
<code><![CDATA[$_POST['funcs'][$routine['item_param_name'][$i]]]]></code>
|
||||
<code><![CDATA[$_POST['item_comment']]]></code>
|
||||
<code><![CDATA[$_POST['item_isdeterministic']]]></code>
|
||||
<code><![CDATA[$_POST['item_name']]]></code>
|
||||
<code><![CDATA[$_POST['item_name']]]></code>
|
||||
@ -3579,17 +3579,12 @@
|
||||
<code><![CDATA[$_POST['item_returnopts_num']]]></code>
|
||||
<code><![CDATA[$_POST['item_returnopts_text']]]></code>
|
||||
<code><![CDATA[$_POST['item_type']]]></code>
|
||||
<code><![CDATA[$itemDefiner]]></code>
|
||||
<code><![CDATA[$itemName]]></code>
|
||||
<code><![CDATA[$itemReturnType]]></code>
|
||||
<code><![CDATA[$itemReturnType]]></code>
|
||||
<code><![CDATA[$itemReturnType]]></code>
|
||||
<code><![CDATA[$itemReturnType]]></code>
|
||||
<code><![CDATA[$itemType]]></code>
|
||||
<code><![CDATA[$itemType]]></code>
|
||||
</PossiblyInvalidArgument>
|
||||
<PossiblyInvalidCast>
|
||||
<code><![CDATA[$_POST['item_comment']]]></code>
|
||||
<code><![CDATA[$_POST['item_isdeterministic']]]></code>
|
||||
<code><![CDATA[$_POST['item_name']]]></code>
|
||||
<code><![CDATA[$_POST['item_original_name']]]></code>
|
||||
@ -3603,7 +3598,6 @@
|
||||
<code><![CDATA[$itemReturnType]]></code>
|
||||
<code><![CDATA[$itemReturnType]]></code>
|
||||
<code><![CDATA[$itemReturnType]]></code>
|
||||
<code><![CDATA[$itemType]]></code>
|
||||
</PossiblyInvalidCast>
|
||||
<PossiblyInvalidIterator>
|
||||
<code><![CDATA[$retval['item_param_dir']]]></code>
|
||||
@ -3611,10 +3605,10 @@
|
||||
<PossiblyInvalidOperand>
|
||||
<code><![CDATA[$_POST['item_original_type']]]></code>
|
||||
<code><![CDATA[$_POST['item_returnlength']]]></code>
|
||||
<code><![CDATA[$itemDefinition]]></code>
|
||||
</PossiblyInvalidOperand>
|
||||
<PossiblyNullArgument>
|
||||
<code><![CDATA[$createRoutine]]></code>
|
||||
<code><![CDATA[$itemType]]></code>
|
||||
<code><![CDATA[$param->type->parameters]]></code>
|
||||
<code><![CDATA[$routine['SPECIFIC_NAME']]]></code>
|
||||
<code><![CDATA[$routine['SPECIFIC_NAME']]]></code>
|
||||
@ -3648,20 +3642,12 @@
|
||||
<code><![CDATA[empty($_POST['editor_process_edit'])]]></code>
|
||||
<code><![CDATA[empty($_POST['funcs'][$routine['item_param_name'][$i]])]]></code>
|
||||
<code><![CDATA[empty($_POST['item_adjust_privileges'])]]></code>
|
||||
<code><![CDATA[empty($_POST['item_comment'])]]></code>
|
||||
<code><![CDATA[empty($_POST['item_returnlength'])]]></code>
|
||||
<code><![CDATA[empty($_POST['item_returnlength'])]]></code>
|
||||
<code><![CDATA[empty($_POST['item_returnopts_num'])]]></code>
|
||||
<code><![CDATA[empty($_POST['item_returnopts_text'])]]></code>
|
||||
<code><![CDATA[empty($itemDefiner)]]></code>
|
||||
<code><![CDATA[empty($itemDefinition)]]></code>
|
||||
<code><![CDATA[empty($itemName)]]></code>
|
||||
<code><![CDATA[empty($itemParamDir[$i])]]></code>
|
||||
<code><![CDATA[empty($itemParamLength)]]></code>
|
||||
<code><![CDATA[empty($itemParamName)]]></code>
|
||||
<code><![CDATA[empty($itemParamName[$i])]]></code>
|
||||
<code><![CDATA[empty($itemParamType)]]></code>
|
||||
<code><![CDATA[empty($itemSecurityType)]]></code>
|
||||
<code><![CDATA[empty($routine['DTD_IDENTIFIER'])]]></code>
|
||||
</RiskyTruthyFalsyComparison>
|
||||
</file>
|
||||
|
||||
@ -9,6 +9,7 @@ use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Controllers\InvocableController;
|
||||
use PhpMyAdmin\Current;
|
||||
use PhpMyAdmin\Database\Routines;
|
||||
use PhpMyAdmin\Database\RoutineType;
|
||||
use PhpMyAdmin\Dbal\DatabaseInterface;
|
||||
use PhpMyAdmin\DbTableExists;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
@ -55,7 +56,7 @@ final readonly class RoutinesController implements InvocableController
|
||||
{
|
||||
$this->response->addScriptFiles(['database/routines.js', 'sql.js']);
|
||||
|
||||
$type = $_REQUEST['type'] ?? null;
|
||||
$type = RoutineType::tryFrom($_REQUEST['type'] ?? '');
|
||||
|
||||
$userPrivileges = $this->userPrivilegesFactory->getPrivileges();
|
||||
|
||||
@ -104,7 +105,7 @@ final readonly class RoutinesController implements InvocableController
|
||||
}
|
||||
|
||||
if (! empty($_POST['editor_process_add']) || ! empty($_POST['editor_process_edit'])) {
|
||||
$output = $this->routines->handleRequestCreateOrEdit($userPrivileges, Current::$database);
|
||||
$output = $this->routines->handleRequestCreateOrEdit($userPrivileges, Current::$database, $request);
|
||||
if ($request->isAjax()) {
|
||||
if (! (Current::$message instanceof Message && Current::$message->isSuccess())) {
|
||||
$this->response->setRequestStatus(false);
|
||||
@ -116,7 +117,7 @@ final readonly class RoutinesController implements InvocableController
|
||||
$routines = Routines::getDetails(
|
||||
$this->dbi,
|
||||
Current::$database,
|
||||
$_POST['item_type'],
|
||||
RoutineType::tryFrom($request->getParsedBodyParamAsString('item_type', '')),
|
||||
$_POST['item_name'],
|
||||
);
|
||||
$routine = $routines[0];
|
||||
@ -451,10 +452,6 @@ final readonly class RoutinesController implements InvocableController
|
||||
}
|
||||
}
|
||||
|
||||
if (! isset($type) || ! in_array($type, ['FUNCTION', 'PROCEDURE'], true)) {
|
||||
$type = null;
|
||||
}
|
||||
|
||||
$totalNumRoutines = Routines::getRoutineCount($this->dbi, Current::$database, $type);
|
||||
$pageSize = $this->config->settings['MaxRoutineList'];
|
||||
$pos = (int) $request->getParam('pos');
|
||||
|
||||
11
src/Database/RoutineType.php
Normal file
11
src/Database/RoutineType.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Database;
|
||||
|
||||
enum RoutineType: string
|
||||
{
|
||||
case Function = 'FUNCTION';
|
||||
case Procedure = 'PROCEDURE';
|
||||
}
|
||||
@ -9,6 +9,7 @@ use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Current;
|
||||
use PhpMyAdmin\Dbal\DatabaseInterface;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Query\Generator as QueryGenerator;
|
||||
use PhpMyAdmin\SqlParser\Parser;
|
||||
@ -68,10 +69,13 @@ class Routines
|
||||
/**
|
||||
* Handle request to create or edit a routine
|
||||
*/
|
||||
public function handleRequestCreateOrEdit(UserPrivileges $userPrivileges, string $db): string
|
||||
{
|
||||
public function handleRequestCreateOrEdit(
|
||||
UserPrivileges $userPrivileges,
|
||||
string $db,
|
||||
ServerRequest $request,
|
||||
): string {
|
||||
$sqlQuery = '';
|
||||
$routineQuery = $this->getQueryFromRequest();
|
||||
$routineQuery = $this->getQueryFromRequest($request);
|
||||
|
||||
// set by getQueryFromRequest()
|
||||
if ($this->errors === []) {
|
||||
@ -627,7 +631,6 @@ class Routines
|
||||
* @param mixed[] $itemParamLength A length or not for the parameter
|
||||
* @param mixed[] $itemParamOpsText An optional charset for the parameter
|
||||
* @param mixed[] $itemParamOpsNum An optional parameter for a $itemParamType NUMBER
|
||||
* @param string $itemType The item type (PROCEDURE/FUNCTION)
|
||||
* @param bool $warnedAboutLength A boolean that will be switched if a the length warning is given
|
||||
*/
|
||||
private function processParamsAndBuild(
|
||||
@ -637,7 +640,7 @@ class Routines
|
||||
array $itemParamLength,
|
||||
array $itemParamOpsText,
|
||||
array $itemParamOpsNum,
|
||||
string $itemType,
|
||||
RoutineType $itemType,
|
||||
bool &$warnedAboutLength,
|
||||
): string {
|
||||
$params = '';
|
||||
@ -650,14 +653,14 @@ class Routines
|
||||
}
|
||||
|
||||
if (
|
||||
$itemType === 'PROCEDURE'
|
||||
$itemType === RoutineType::Procedure
|
||||
&& ! empty($itemParamDir[$i])
|
||||
&& in_array($itemParamDir[$i], $this->directions, true)
|
||||
) {
|
||||
$params .= $itemParamDir[$i] . ' '
|
||||
. Util::backquote($itemParamName[$i])
|
||||
. ' ' . $itemParamType[$i];
|
||||
} elseif ($itemType === 'FUNCTION') {
|
||||
} elseif ($itemType === RoutineType::Function) {
|
||||
$params .= Util::backquote($itemParamName[$i])
|
||||
. ' ' . $itemParamType[$i];
|
||||
} elseif (! $warnedAboutDir) {
|
||||
@ -775,14 +778,14 @@ class Routines
|
||||
*
|
||||
* @return string The CREATE [ROUTINE | PROCEDURE] query.
|
||||
*/
|
||||
public function getQueryFromRequest(): string
|
||||
public function getQueryFromRequest(ServerRequest $request): string
|
||||
{
|
||||
$itemType = $_POST['item_type'] ?? '';
|
||||
$itemDefiner = $_POST['item_definer'] ?? '';
|
||||
$itemName = $_POST['item_name'] ?? '';
|
||||
$itemType = RoutineType::tryFrom($request->getParsedBodyParamAsString('item_type', ''));
|
||||
$itemDefiner = $request->getParsedBodyParamAsString('item_definer', '');
|
||||
$itemName = $request->getParsedBodyParamAsString('item_name', '');
|
||||
|
||||
$query = 'CREATE ';
|
||||
if (! empty($itemDefiner)) {
|
||||
if ($itemDefiner !== '') {
|
||||
if (str_contains($itemDefiner, '@')) {
|
||||
$arr = explode('@', $itemDefiner);
|
||||
|
||||
@ -804,16 +807,13 @@ class Routines
|
||||
}
|
||||
}
|
||||
|
||||
if ($itemType === 'FUNCTION' || $itemType === 'PROCEDURE') {
|
||||
$query .= $itemType . ' ';
|
||||
if ($itemType !== null) {
|
||||
$query .= $itemType->value . ' ';
|
||||
} else {
|
||||
$this->errors[] = sprintf(
|
||||
__('Invalid routine type: "%s"'),
|
||||
htmlspecialchars($itemType),
|
||||
);
|
||||
$this->errors[] = __('Invalid routine type!');
|
||||
}
|
||||
|
||||
if (! empty($itemName)) {
|
||||
if ($itemName !== '') {
|
||||
$query .= Util::backquote($itemName);
|
||||
} else {
|
||||
$this->errors[] = __('You must provide a routine name!');
|
||||
@ -821,18 +821,18 @@ class Routines
|
||||
|
||||
$warnedAboutLength = false;
|
||||
|
||||
$itemParamName = $_POST['item_param_name'] ?? '';
|
||||
$itemParamType = $_POST['item_param_type'] ?? '';
|
||||
$itemParamLength = $_POST['item_param_length'] ?? '';
|
||||
$itemParamDir = (array) ($_POST['item_param_dir'] ?? []);
|
||||
$itemParamOpsText = (array) ($_POST['item_param_opts_text'] ?? []);
|
||||
$itemParamOpsNum = (array) ($_POST['item_param_opts_num'] ?? []);
|
||||
$itemParamName = $request->getParsedBodyParam('item_param_name', '');
|
||||
$itemParamType = $request->getParsedBodyParam('item_param_type', '');
|
||||
$itemParamLength = $request->getParsedBodyParam('item_param_length', '');
|
||||
$itemParamDir = (array) $request->getParsedBodyParam('item_param_dir', []);
|
||||
$itemParamOpsText = (array) $request->getParsedBodyParam('item_param_opts_text', []);
|
||||
$itemParamOpsNum = (array) $request->getParsedBodyParam('item_param_opts_num', []);
|
||||
|
||||
$params = '';
|
||||
if (
|
||||
! empty($itemParamName)
|
||||
&& ! empty($itemParamType)
|
||||
&& ! empty($itemParamLength)
|
||||
$itemParamName !== []
|
||||
&& $itemParamType !== []
|
||||
&& $itemParamLength !== []
|
||||
&& is_array($itemParamName)
|
||||
&& is_array($itemParamType)
|
||||
&& is_array($itemParamLength)
|
||||
@ -850,34 +850,33 @@ class Routines
|
||||
}
|
||||
|
||||
$query .= '(' . $params . ') ';
|
||||
if ($itemType === 'FUNCTION') {
|
||||
if ($itemType === RoutineType::Function) {
|
||||
$query = $this->processFunctionSpecificParameters($query, $warnedAboutLength);
|
||||
}
|
||||
|
||||
if (! empty($_POST['item_comment'])) {
|
||||
$query .= 'COMMENT ' . $this->dbi->quoteString($_POST['item_comment']) . ' ';
|
||||
$itemComment = $request->getParsedBodyParamAsString('item_comment', '');
|
||||
if ($itemComment !== '') {
|
||||
$query .= 'COMMENT ' . $this->dbi->quoteString($itemComment) . ' ';
|
||||
}
|
||||
|
||||
if (isset($_POST['item_isdeterministic'])) {
|
||||
if ($request->hasBodyParam('item_isdeterministic')) {
|
||||
$query .= 'DETERMINISTIC ';
|
||||
} else {
|
||||
$query .= 'NOT DETERMINISTIC ';
|
||||
}
|
||||
|
||||
$itemSqlDataAccess = $_POST['item_sqldataaccess'] ?? '';
|
||||
$itemSqlDataAccess = $request->getParsedBodyParamAsString('item_sqldataaccess', '');
|
||||
if (in_array($itemSqlDataAccess, $this->sqlDataAccess, true)) {
|
||||
$query .= $itemSqlDataAccess . ' ';
|
||||
}
|
||||
|
||||
$itemSecurityType = $_POST['item_securitytype'] ?? '';
|
||||
if (! empty($itemSecurityType)) {
|
||||
if ($itemSecurityType === 'DEFINER' || $itemSecurityType === 'INVOKER') {
|
||||
$query .= 'SQL SECURITY ' . $itemSecurityType . ' ';
|
||||
}
|
||||
$itemSecurityType = $request->getParsedBodyParamAsString('item_securitytype', '');
|
||||
if ($itemSecurityType === 'DEFINER' || $itemSecurityType === 'INVOKER') {
|
||||
$query .= 'SQL SECURITY ' . $itemSecurityType . ' ';
|
||||
}
|
||||
|
||||
$itemDefinition = $_POST['item_definition'] ?? '';
|
||||
if (! empty($itemDefinition)) {
|
||||
$itemDefinition = $request->getParsedBodyParamAsString('item_definition', '');
|
||||
if ($itemDefinition !== '') {
|
||||
$query .= $itemDefinition;
|
||||
} else {
|
||||
$this->errors[] = __('You must provide a routine definition.');
|
||||
@ -1189,23 +1188,21 @@ class Routines
|
||||
* returns details about the PROCEDUREs or FUNCTIONs for a specific database
|
||||
* or details about a specific routine
|
||||
*
|
||||
* @param string $db db name
|
||||
* @param string|null $which PROCEDURE | FUNCTION or null for both
|
||||
* @param string $name name of the routine (to fetch a specific routine)
|
||||
* @param string $name name of the routine (to fetch a specific routine)
|
||||
*
|
||||
* @return Routine[]
|
||||
*/
|
||||
public static function getDetails(
|
||||
DatabaseInterface $dbi,
|
||||
string $db,
|
||||
string|null $which = null,
|
||||
RoutineType|null $which = null,
|
||||
string $name = '',
|
||||
int $limit = 0,
|
||||
int $offset = 0,
|
||||
): array {
|
||||
$query = QueryGenerator::getInformationSchemaRoutinesRequest(
|
||||
$dbi->quoteString($db),
|
||||
in_array($which, ['FUNCTION', 'PROCEDURE'], true) ? $which : null,
|
||||
$which,
|
||||
$name === '' ? null : $dbi->quoteString($name),
|
||||
$limit,
|
||||
$offset,
|
||||
@ -1226,11 +1223,11 @@ class Routines
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public static function getRoutineCount(DatabaseInterface $dbi, string $db, string|null $which = null): int
|
||||
public static function getRoutineCount(DatabaseInterface $dbi, string $db, RoutineType|null $which = null): int
|
||||
{
|
||||
$query = QueryGenerator::getInformationSchemaRoutinesCountRequest(
|
||||
$dbi->quoteString($db),
|
||||
in_array($which, ['FUNCTION', 'PROCEDURE'], true) ? $which : null,
|
||||
$which,
|
||||
);
|
||||
|
||||
return (int) $dbi->fetchValue($query);
|
||||
@ -1260,38 +1257,14 @@ class Routines
|
||||
* @return array<int, string>
|
||||
* @psalm-return list<non-empty-string>
|
||||
*/
|
||||
public static function getFunctionNames(DatabaseInterface $dbi, string $db): array
|
||||
public static function getNames(DatabaseInterface $dbi, string $db, RoutineType $type): array
|
||||
{
|
||||
/** @psalm-var list<array{Db: string, Name: string, Type: string}> $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<int, string>
|
||||
* @psalm-return list<non-empty-string>
|
||||
*/
|
||||
public static function getProcedureNames(DatabaseInterface $dbi, string $db): array
|
||||
{
|
||||
/** @psalm-var list<array{Db: string, Name: string, Type: string}> $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<non-empty-string> $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;
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Query;
|
||||
|
||||
use PhpMyAdmin\Database\RoutineType;
|
||||
use PhpMyAdmin\Triggers\Trigger;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
@ -175,7 +176,7 @@ class Generator
|
||||
|
||||
public static function getInformationSchemaRoutinesRequest(
|
||||
string $quotedDbName,
|
||||
string|null $routineType,
|
||||
RoutineType|null $routineType,
|
||||
string|null $quotedRoutineName,
|
||||
int $limit = 0,
|
||||
int $offset = 0,
|
||||
@ -189,7 +190,7 @@ class Generator
|
||||
. ' WHERE `ROUTINE_SCHEMA` ' . Util::getCollateForIS()
|
||||
. ' = ' . $quotedDbName;
|
||||
if ($routineType !== null) {
|
||||
$query .= " AND `ROUTINE_TYPE` = '" . $routineType . "'";
|
||||
$query .= " AND `ROUTINE_TYPE` = '" . $routineType->value . "'";
|
||||
}
|
||||
|
||||
if ($quotedRoutineName !== null) {
|
||||
@ -211,7 +212,7 @@ class Generator
|
||||
|
||||
public static function getInformationSchemaRoutinesCountRequest(
|
||||
string $quotedDbName,
|
||||
string|null $routineType,
|
||||
RoutineType|null $routineType,
|
||||
string|null $quotedRoutineName = null,
|
||||
): string {
|
||||
$query = 'SELECT COUNT(*) AS `count`'
|
||||
@ -219,7 +220,7 @@ class Generator
|
||||
. ' WHERE `ROUTINE_SCHEMA` ' . Util::getCollateForIS()
|
||||
. ' = ' . $quotedDbName;
|
||||
if ($routineType !== null) {
|
||||
$query .= " AND `ROUTINE_TYPE` = '" . $routineType . "'";
|
||||
$query .= " AND `ROUTINE_TYPE` = '" . $routineType->value . "'";
|
||||
}
|
||||
|
||||
if ($quotedRoutineName !== null) {
|
||||
|
||||
@ -3082,16 +3082,13 @@ class Privileges
|
||||
*/
|
||||
public function getRoutineType(string $dbname, string $routineName): string
|
||||
{
|
||||
$routineData = Routines::getDetails($this->dbi, $dbname);
|
||||
$routineName = mb_strtolower($routineName);
|
||||
$routineData = Routines::getDetails($this->dbi, $dbname, name: $routineName);
|
||||
|
||||
foreach ($routineData as $routine) {
|
||||
if (mb_strtolower($routine->name) === $routineName) {
|
||||
return $routine->type;
|
||||
}
|
||||
if ($routineData === []) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '';
|
||||
return $routineData[0]->type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -7,8 +7,10 @@ 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\Http\Factory\ServerRequestFactory;
|
||||
use PhpMyAdmin\Tests\AbstractTestCase;
|
||||
use PhpMyAdmin\Types;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
@ -253,7 +255,9 @@ class RoutinesTest extends AbstractTestCase
|
||||
|
||||
unset($_POST);
|
||||
$_POST = $request;
|
||||
self::assertSame($query, $routines->getQueryFromRequest());
|
||||
$request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/')
|
||||
->withParsedBody($request);
|
||||
self::assertSame($query, $routines->getQueryFromRequest($request));
|
||||
self::assertSame($numErr, $routines->getErrorCount());
|
||||
|
||||
// reset
|
||||
@ -476,18 +480,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 +499,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 +515,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 +534,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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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`',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user