1
0
mirror of https://github.com/vrana/adminer.git synced 2025-08-30 01:30:12 +02:00

Compare commits

...

14 Commits

Author SHA1 Message Date
Peter Knut
507f335371 Release 4.9.3 2024-10-02 17:07:09 +02:00
Peter Knut
ea314b8103 Hide invalid edit form if table record is not found 2024-10-02 09:35:59 +02:00
Peter Knut
e250470768 PostgreSQL: Fix editing record that contains a field with GENERATED ALWAYS default value
Fields with GENERATED ALWAYS default values are also disabled.

Thanks to PurpleTape (https://github.com/adminerevo/adminerevo/issues/201).
2024-10-02 00:29:24 +02:00
Peter Knut
2fa42d50eb Fix using undefined Min_DB::info property 2024-10-01 23:37:07 +02:00
Peter Knut
a366b7af09 MySQL: Fix editing user's proxy privilege, refactoring
- Uncheck all other priviledges if 'All privileges' is checked.
- Refactor related functions.
2024-10-01 23:22:26 +02:00
Peter Knut
b039a39e4d Bigger font size for code blocks 2024-10-01 09:07:21 +02:00
SeaEagle
08e48c8641 MySQL: Fix where clause for JSON column
Issue: https://github.com/adminerevo/adminerevo/issues/175
2024-10-01 09:06:20 +02:00
Peter Knut
78c2041cfd Fix background color of <pre> used as edit field 2024-10-01 00:33:47 +02:00
Peter Knut
5d7c5fa268 Do not include unchanged PARTITION BY definition into ALTER TABLE query 2024-09-22 00:33:55 +02:00
Peter Knut
8f1db4cf6f Add helper methods for dumping variable to the output 2024-09-21 22:34:38 +02:00
Peter Knut
9daa88acca MariaDB: Fix comparing CURRENT_TIMESTAMP definition while altering a table 2024-09-21 22:20:08 +02:00
Peter Knut
aa519b78ca MySQL, PostgreSQL: Fix queries splitting and string constants
Thanks to alxivnov (https://github.com/vrana/adminer/pull/490).
2024-09-21 09:28:50 +02:00
Michael Graß
aee800efed Do not limit unlimited memory, fix number conversion warning 2024-09-20 22:28:46 +02:00
Peter Knut
06d0f957d5 Bump version to 4.9.3-dev 2024-09-18 10:57:48 +02:00
16 changed files with 285 additions and 81 deletions

View File

@@ -82,20 +82,39 @@ if ($_POST && !process_fields($row["fields"]) && !$error) {
}
$partitioning = "";
if ($partition_by[$row["partition_by"]]) {
$partitions = array();
if ($row["partition_by"] == 'RANGE' || $row["partition_by"] == 'LIST') {
foreach (array_filter($row["partition_names"]) as $key => $val) {
$value = $row["partition_values"][$key];
$partitions[] = "\n PARTITION " . idf_escape($val) . " VALUES " . ($row["partition_by"] == 'RANGE' ? "LESS THAN" : "IN") . ($value != "" ? " ($value)" : " MAXVALUE"); //! SQL injection
if (support("partitioning")) {
if (isset($partition_by[$row["partition_by"]])) {
$params = array_filter($row, function ($key) {
return preg_match('~^partition~', $key);
}, ARRAY_FILTER_USE_KEY);
foreach ($params["partition_names"] as $key => $name) {
if ($name === "") {
unset($params["partition_names"][$key]);
unset($params["partition_values"][$key]);
}
}
if ($params != get_partitions_info($TABLE)) {
$partitions = [];
if ($params["partition_by"] == 'RANGE' || $params["partition_by"] == 'LIST') {
foreach ($params["partition_names"] as $key => $name) {
$value = $params["partition_values"][$key];
$partitions[] = "\n PARTITION " . idf_escape($name) . " VALUES " . ($params["partition_by"] == 'RANGE' ? "LESS THAN" : "IN") . ($value != "" ? " ($value)" : " MAXVALUE"); //! SQL injection
}
}
// $params["partition"] can be expression, not only column
$partitioning .= "\nPARTITION BY {$params["partition_by"]}({$params["partition"]})";
if ($partitions) {
$partitioning .= " (" . implode(",", $partitions) . "\n)";
} elseif ($params["partitions"]) {
$partitioning .= " PARTITIONS " . (int)$params["partitions"];
}
}
} elseif (preg_match("~partitioned~", $table_status["Create_options"])) {
$partitioning .= "\nREMOVE PARTITIONING";
}
$partitioning .= "\nPARTITION BY $row[partition_by]($row[partition])" . ($partitions // $row["partition"] can be expression, not only column
? " (" . implode(",", $partitions) . "\n)"
: ($row["partitions"] ? " PARTITIONS " . (+$row["partitions"]) : "")
);
} elseif (support("partitioning") && preg_match("~partitioned~", $table_status["Create_options"])) {
$partitioning .= "\nREMOVE PARTITIONING";
}
$message = lang('Table has been altered.');
@@ -141,13 +160,9 @@ if (!$_POST) {
}
if (support("partitioning")) {
$from = "FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = " . q(DB) . " AND TABLE_NAME = " . q($TABLE);
$result = $connection->query("SELECT PARTITION_METHOD, PARTITION_ORDINAL_POSITION, PARTITION_EXPRESSION $from ORDER BY PARTITION_ORDINAL_POSITION DESC LIMIT 1");
list($row["partition_by"], $row["partitions"], $row["partition"]) = $result->fetch_row();
$partitions = get_key_vals("SELECT PARTITION_NAME, PARTITION_DESCRIPTION $from AND PARTITION_NAME != '' ORDER BY PARTITION_ORDINAL_POSITION");
$partitions[""] = "";
$row["partition_names"] = array_keys($partitions);
$row["partition_values"] = array_values($partitions);
$row += get_partitions_info($TABLE);
$row["partition_names"][] = "";
$row["partition_values"][] = "";
}
}
}

View File

@@ -637,6 +637,10 @@ WHERE sys1.xtype = 'TR' AND sys2.name = " . q($table)
return false;
}
function is_c_style_escapes() {
return true;
}
function show_status() {
return array();
}

View File

@@ -1074,6 +1074,16 @@ if (!defined("DRIVER")) {
return $strictMode;
}
function is_c_style_escapes() {
static $c_style = null;
if ($c_style === null) {
$c_style = strpos(get_key_vals("SHOW VARIABLES LIKE 'sql_mode'")["sql_mode"], 'NO_BACKSLASH_ESCAPES') === false;
}
return $c_style;
}
/** Get process list
* @return array ($row)
*/

View File

@@ -493,6 +493,10 @@ AND c_src.TABLE_NAME = " . q($table);
return false;
}
function is_c_style_escapes() {
return true;
}
function process_list() {
return get_rows('SELECT sess.process AS "process", sess.username AS "user", sess.schemaname AS "schema", sess.status AS "status", sess.wait_class AS "wait_class", sess.seconds_in_wait AS "seconds_in_wait", sql.sql_text AS "sql_text", sess.machine AS "machine", sess.port AS "port"
FROM v$session sess LEFT OUTER JOIN v$sql sql

View File

@@ -885,6 +885,16 @@ AND typelem = 0"
return false;
}
function is_c_style_escapes() {
static $c_style = null;
if ($c_style === null) {
$c_style = get_vals("SHOW standard_conforming_strings")[0] == "off";
}
return $c_style;
}
function process_list() {
return get_rows("SELECT * FROM pg_stat_activity ORDER BY " . (min_version(9.2) ? "pid" : "procpid"));
}
@@ -949,6 +959,7 @@ AND typelem = 0"
"char|text" => "||",
)
),
'c_style_escapes' => true,
);
}
}

View File

@@ -771,6 +771,10 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
return false;
}
function is_c_style_escapes() {
return true;
}
function show_status() {
$return = array();
foreach (get_vals("PRAGMA compile_options") as $option) {

View File

@@ -6,6 +6,7 @@ function adminer_errors($errno, $errstr) {
error_reporting(6135); // errors and warnings
set_error_handler('adminer_errors', E_WARNING);
include "../adminer/include/debug.inc.php";
include "../adminer/include/coverage.inc.php";
// disable filter.default

View File

@@ -0,0 +1,14 @@
<?php
function dump($value)
{
echo "<pre>";
var_export($value);
echo "</pre>\n";
}
function dumpe($value)
{
dump($value);
exit;
}

View File

@@ -221,12 +221,17 @@ function process_type($field, $collate = "COLLATE") {
* @return array array("field", "type", "NULL", "DEFAULT", "ON UPDATE", "COMMENT", "AUTO_INCREMENT")
*/
function process_field($field, $type_field) {
// MariaDB exports CURRENT_TIMESTAMP as a function.
if ($field["on_update"]) {
$field["on_update"] = str_ireplace("current_timestamp()", "CURRENT_TIMESTAMP", $field["on_update"]);
}
return array(
idf_escape(trim($field["field"])),
process_type($type_field),
($field["null"] ? " NULL" : " NOT NULL"), // NULL for timestamp
default_value($field),
(preg_match('~timestamp|datetime~', $field["type"]) && $field["on_update"] ? " ON UPDATE $field[on_update]" : ""),
(preg_match('~timestamp|datetime~', $field["type"]) && $field["on_update"] ? " ON UPDATE " . $field["on_update"] : ""),
(support("comment") && $field["comment"] != "" ? " COMMENT " . q($field["comment"]) : ""),
($field["auto_increment"] ? auto_increment() : null),
);
@@ -240,10 +245,13 @@ function default_value($field) {
$default = $field["default"];
if ($default === null) return "";
if (preg_match('~^GENERATED ~i', $default)) {
if (stripos($default, "GENERATED ") === 0) {
return " $default";
}
// MariaDB exports CURRENT_TIMESTAMP as a function.
$default = str_ireplace("current_timestamp()", "CURRENT_TIMESTAMP", $default);
$quote = preg_match('~char|binary|text|enum|set~', $field["type"]) || preg_match('~^(?![a-z])~i', $default);
return " DEFAULT " . ($quote ? q($default) : $default);
@@ -376,25 +384,43 @@ function normalize_enum($match) {
return "'" . str_replace("'", "''", addcslashes(stripcslashes(str_replace($match[0][0] . $match[0][0], $match[0][0], substr($match[0], 1, -1))), '\\')) . "'";
}
/** Issue grant or revoke commands
* @param string GRANT or REVOKE
* @param array
* @param string
* @param string
* @return bool
*/
function grant($grant, $privileges, $columns, $on) {
if (!$privileges) {
return true;
/**
* Issue grant or revoke commands.
*
* @param bool $grant
* @param array $privileges
* @param string $columns
* @param string $on
* @param string $user
*
* @return bool
*/
function grant($grant, array $privileges, $columns, $on, $user) {
if (!$privileges) return true;
if ($privileges == ["ALL PRIVILEGES", "GRANT OPTION"]) {
if ($grant) {
return (bool) queries("GRANT ALL PRIVILEGES ON $on TO $user WITH GRANT OPTION");
} else {
return queries("REVOKE ALL PRIVILEGES ON $on FROM $user") &&
queries("REVOKE GRANT OPTION ON $on FROM $user");
}
}
if ($privileges == array("ALL PRIVILEGES", "GRANT OPTION")) {
// can't be granted or revoked together
return ($grant == "GRANT"
? queries("$grant ALL PRIVILEGES$on WITH GRANT OPTION")
: queries("$grant ALL PRIVILEGES$on") && queries("$grant GRANT OPTION$on")
);
if ($privileges == ["GRANT OPTION", "PROXY"]) {
if ($grant) {
return (bool) queries("GRANT PROXY ON $on TO $user WITH GRANT OPTION");
} else {
return (bool) queries("REVOKE PROXY ON $on FROM $user");
}
}
return queries("$grant " . preg_replace('~(GRANT OPTION)\([^)]*\)~', '\1', implode("$columns, ", $privileges) . $columns) . $on);
return (bool) queries(
($grant ? "GRANT " : "REVOKE ") .
preg_replace('~(GRANT OPTION)\([^)]*\)~', '$1', implode("$columns, ", $privileges) . $columns) .
" ON $on " .
($grant ? "TO " : "FROM ") . $user
);
}
/** Drop old object and create a new one
@@ -523,9 +549,9 @@ function tar_file($filename, $tmp_file) {
function ini_bytes($ini) {
$val = ini_get($ini);
switch (strtolower(substr($val, -1))) {
case 'g': $val *= 1024; // no break
case 'm': $val *= 1024; // no break
case 'k': $val *= 1024;
case 'g': $val = (int)$val * 1024; // no break
case 'm': $val = (int)$val * 1024; // no break
case 'k': $val = (int)$val * 1024;
}
return $val;
}

View File

@@ -477,24 +477,36 @@ function escape_key($key) {
*/
function where($where, $fields = array()) {
global $connection, $jush;
$return = array();
$conditions = [];
foreach ((array) $where["where"] as $key => $val) {
$key = bracket_escape($key, 1); // 1 - back
$column = escape_key($key);
$return[] = $column
. ($jush == "sql" && is_numeric($val) && preg_match('~\.~', $val) ? " LIKE " . q($val) // LIKE because of floats but slow with ints
: ($jush == "mssql" ? " LIKE " . q(preg_replace('~[_%[]~', '[\0]', $val)) // LIKE because of text
: " = " . unconvert_field($fields[$key], q($val))
))
; //! enum and set
if ($jush == "sql" && preg_match('~char|text~', $fields[$key]["type"]) && preg_match("~[^ -@]~", $val)) { // not just [a-z] to catch non-ASCII characters
$return[] = "$column = " . q($val) . " COLLATE " . charset($connection) . "_bin";
if ($jush == "sql" && $fields[$key]["type"] == "json") {
$conditions[] = "$column = CAST(" . q($val) . " AS JSON)";
} elseif ($jush == "sql" && is_numeric($val) && strpos($val, ".") !== false) {
// LIKE because of floats but slow with ints.
$conditions[] = "$column LIKE " . q($val);
} elseif ($jush == "mssql") {
// LIKE because of text.
$conditions[] = "$column LIKE " . q(preg_replace('~[_%[]~', '[\0]', $val));
} else {
$conditions[] = "$column = " . unconvert_field($fields[$key], q($val));
}
// Not just [a-z] to catch non-ASCII characters.
if ($jush == "sql" && preg_match('~char|text~', $fields[$key]["type"]) && preg_match("~[^ -@]~", $val)) {
$conditions[] = "$column = " . q($val) . " COLLATE " . charset($connection) . "_bin";
}
}
foreach ((array) $where["null"] as $key) {
$return[] = escape_key($key) . " IS NULL";
$conditions[] = escape_key($key) . " IS NULL";
}
return implode(" AND ", $return);
return implode(" AND ", $conditions);
}
/** Create SQL condition from query string
@@ -935,8 +947,9 @@ function enum_input($type, $attrs, $field, $value, $empty = null) {
*/
function input($field, $value, $function) {
global $types, $adminer, $jush;
$name = h(bracket_escape($field["field"]));
echo "<td class='function'>";
if (is_array($value) && !$function) {
$args = array($value);
if (version_compare(PHP_VERSION, 5.4) >= 0) {
@@ -950,13 +963,18 @@ function input($field, $value, $function) {
$function = null;
}
$functions = (isset($_GET["select"]) || $reset ? array("orig" => lang('original')) : array()) + $adminer->editFunctions($field);
$attrs = " name='fields[$name]'";
$disabled = stripos($field["default"], "GENERATED ALWAYS AS ") === 0 ? " disabled=''" : "";
$attrs = " name='fields[$name]' $disabled";
echo "<td class='function'>";
if ($field["type"] == "enum") {
echo h($functions[""]) . "<td>" . $adminer->editInput($_GET["edit"], $field, $attrs, $value);
} else {
$has_function = (in_array($function, $functions) || isset($functions[$function]));
echo (count($functions) > 1
? "<select name='function[$name]'>" . optionlist($functions, $function === null || $has_function ? $function : "") . "</select>"
? "<select name='function[$name]' $disabled>" . optionlist($functions, $function === null || $has_function ? $function : "") . "</select>"
. on_help("getTarget(event).value.replace(/^SQL\$/, '')", 1)
. script("qsl('select').onchange = functionChange;", "")
: h(reset($functions))
@@ -1021,6 +1039,11 @@ function input($field, $value, $function) {
*/
function process_input($field) {
global $adminer, $driver;
if (stripos($field["default"], "GENERATED ALWAYS AS ") === 0) {
return null;
}
$idf = bracket_escape($field["field"]);
$function = $_POST["function"][$idf];
$value = $_POST["fields"][$idf];
@@ -1111,6 +1134,27 @@ function search_tables() {
echo ($sep ? "<p class='message'>" . lang('No tables.') : "</ul>") . "\n";
}
/**
* @param string $table
* @return array
*/
function get_partitions_info($table) {
global $connection;
$from = "FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = " . q(DB) . " AND TABLE_NAME = " . q($table);
$result = $connection->query("SELECT PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_ORDINAL_POSITION $from ORDER BY PARTITION_ORDINAL_POSITION DESC LIMIT 1");
$info = [];
list($info["partition_by"], $info["partition"], $info["partitions"]) = $result->fetch_row();
$partitions = get_key_vals("SELECT PARTITION_NAME, PARTITION_DESCRIPTION $from AND PARTITION_NAME != '' ORDER BY PARTITION_ORDINAL_POSITION");
$info["partition_names"] = array_keys($partitions);
$info["partition_values"] = array_values($partitions);
return $info;
}
/** Send headers for export
* @param string
* @param bool
@@ -1441,6 +1485,7 @@ function edit_form($table, $fields, $row, $update) {
$adminer->editRowPrint($table, $fields, $row, $update);
if ($row === false) {
echo "<p class='error'>" . lang('No rows.') . "\n";
return;
}
?>
<form action="" method="post" enctype="multipart/form-data" id="form">

View File

@@ -1,2 +1,2 @@
<?php
$VERSION = "4.9.2";
$VERSION = "4.9.3";

View File

@@ -32,8 +32,8 @@ if (!$error && $_POST) {
}
if (is_string($query)) { // get_file() returns error as number, fread() as false
if (function_exists('memory_get_usage')) {
@ini_set("memory_limit", max(ini_bytes("memory_limit"), 2 * strlen($query) + memory_get_usage() + 8e6)); // @ - may be disabled, 2 - substr and trim, 8e6 - other variables
if (function_exists('memory_get_usage') && ($memory_limit = ini_bytes("memory_limit")) != "-1") {
@ini_set("memory_limit", max($memory_limit, 2 * strlen($query) + memory_get_usage() + 8e6)); // @ - may be disabled, 2 - substr and trim, 8e6 - other variables
}
if ($query != "" && strlen($query) < 1e6) { // don't add big queries
@@ -81,7 +81,21 @@ if (!$error && $_POST) {
$offset = $pos + strlen($found);
if ($found && rtrim($found) != $delimiter) { // find matching quote or comment end
while (preg_match('(' . ($found == '/*' ? '\*/' : ($found == '[' ? ']' : (preg_match('~^-- |^#~', $found) ? "\n" : preg_quote($found) . "|\\\\."))) . '|$)s', $query, $match, PREG_OFFSET_CAPTURE, $offset)) { //! respect sql_mode NO_BACKSLASH_ESCAPES
$c_style_escapes = is_c_style_escapes() || ($jush == "pgsql" && ($pos > 0 && strtolower($query[$pos - 1]) == "e"));
$pattern = '(';
if ($found == '/*') {
$pattern .= '\*/';
} elseif ($found == '[') {
$pattern .= ']';
} elseif (preg_match('~^-- |^#~', $found)) {
$pattern .= "\n";
} else {
$pattern .= preg_quote($found) . ($c_style_escapes ? "|\\\\." : "");
}
$pattern .= '|$)s';
while (preg_match($pattern, $query, $match, PREG_OFFSET_CAPTURE, $offset)) {
$s = $match[0][0];
if (!$s && $fp && !feof($fp)) {
$query .= fread($fp, 1e5);
@@ -169,7 +183,8 @@ if (!$error && $_POST) {
stop_session();
}
if (!$_POST["only_errors"]) {
echo "<p class='message' title='" . h($connection->info) . "'>" . lang('Query executed OK, %d row(s) affected.', $affected) . "$time\n";
$title = isset($connection->info) ? "title='" . h($connection->info) . "'" : "";
echo "<p class='message' $title>" . lang('Query executed OK, %d row(s) affected.', $affected) . "$time\n";
}
}
echo ($warnings ? "<div id='$warnings_id' class='hidden'>\n$warnings</div>\n" : "");

View File

@@ -19,15 +19,18 @@ fieldset { display: inline; vertical-align: top; padding: .5em .8em; margin: .8e
p { margin: .8em 20px 0 0; }
img { vertical-align: middle; border: 0; }
td img { max-width: 200px; max-height: 200px; }
code { background: #eee; }
tbody tr:hover td, tbody tr:hover th { background: #eee; }
code { font-size: 110%; padding: 1px 2px; background: #eee; }
pre { margin: 1em 0 0; }
pre, textarea { font: 100%/1.25 monospace; }
pre code { display: block; font-size: 100%; }
pre, textarea { font: 110%/1.25 monospace; }
pre.jush { background: #fff; }
input, select { vertical-align: middle; }
input.default { box-shadow: 1px 1px 1px #777; }
input.required { box-shadow: 1px 1px 1px red; }
input.maxlength { box-shadow: 1px 1px 1px red; }
input.wayoff { left: -1000px; position: absolute; }
.center { text-align: center; }
.block { display: block; }
.version { color: #777; font-size: 67%; }
.js .hidden, .nojs .jsonly { display: none; }

View File

@@ -211,13 +211,21 @@ function tableCheck() {
}
}
/** Uncheck single element
* @param string
*/
/**
* Uncheck single element.
*/
function formUncheck(id) {
var el = qs('#' + id);
el.checked = false;
trCheck(el);
formUncheckAll("#" + id);
}
/**
* Uncheck elements matched by selector.
*/
function formUncheckAll(selector) {
for (const element of qsa(selector)) {
element.checked = false;
trCheck(element);
}
}
/** Get number of checked elements matching given name

View File

@@ -85,8 +85,8 @@ if ($_POST && !$error) {
unset($grants[$object]);
}
if (preg_match('~^(.+)\s*(\(.*\))?$~U', $object, $match) && (
!grant("REVOKE", $revoke, $match[2], " ON $match[1] FROM $new_user") //! SQL injection
|| !grant("GRANT", $grant, $match[2], " ON $match[1] TO $new_user")
!grant(false, $revoke, $match[2], $match[1], $new_user) //! SQL injection
|| !grant(true, $grant, $match[2], $match[1], $new_user)
)) {
$error = true;
break;
@@ -100,7 +100,7 @@ if ($_POST && !$error) {
} elseif (!isset($_GET["grant"])) {
foreach ($grants as $object => $revoke) {
if (preg_match('~^(.+)(\(.*\))?$~U', $object, $match)) {
grant("REVOKE", array_keys($revoke), $match[2], " ON $match[1] FROM $new_user");
grant(false, array_keys($revoke), $match[2], $match[1], $new_user);
}
}
}
@@ -150,33 +150,63 @@ foreach ($grants as $object => $grant) {
}
echo "</thead>\n";
foreach (array(
foreach ([
"" => "",
"Server Admin" => lang('Server'),
"Databases" => lang('Database'),
"Tables" => lang('Table'),
"Columns" => lang('Column'),
"Procedures" => lang('Routine'),
) as $context => $desc) {
] as $context => $desc) {
foreach ((array) $privileges[$context] as $privilege => $comment) {
echo "<tr" . odd() . "><td" . ($desc ? ">$desc<td" : " colspan='2'") . ' lang="en" title="' . h($comment) . '">' . h($privilege);
echo "<tr" . odd() . ">";
if ($desc) {
echo "<td>$desc</td>";
}
echo "<td" . (!$desc ? " colspan='2'" : "") . ' lang="en" title="' . h($comment) . '">' . h($privilege) . "</td>";
$i = 0;
foreach ($grants as $object => $grant) {
$name = "'grants[$i][" . h(strtoupper($privilege)) . "]'";
$value = $grant[strtoupper($privilege)];
if ($context == "Server Admin" && $object != (isset($grants["*.*"]) ? "*.*" : ".*")) {
echo "<td>";
$proxiedUser = strpos($object, "@") !== false;
$newObject = $object == ".*";
$allPrivileges = $privilege == "All privileges";
$grantOption = $privilege == "Grant option";
if ($object == "*.*" && $privilege == "Proxy") {
echo "<td></td>";
} elseif ($proxiedUser && $privilege != "Proxy" && !$grantOption) {
echo "<td></td>";
} elseif ($context == "Server Admin" && $object != (isset($grants["*.*"]) ? "*.*" : ".*") && !(($proxiedUser || $newObject) && $privilege == "Proxy")) {
echo "<td></td>";
} elseif (isset($_GET["grant"])) {
echo "<td><select name=$name><option><option value='1'" . ($value ? " selected" : "") . ">" . lang('Grant') . "<option value='0'" . ($value == "0" ? " selected" : "") . ">" . lang('Revoke') . "</select>";
echo "<td><select name=$name>" .
"<option></option>" .
"<option value='1'" . ($value ? " selected" : "") . ">" . lang('Grant') . "</option>" .
"<option value='0'" . ($value == "0" ? " selected" : "") . ">" . lang('Revoke') . "</option>" .
"</select></td>";
} else {
echo "<td align='center'><label class='block'>";
echo "<input type='checkbox' name=$name value='1'" . ($value ? " checked" : "") . ($privilege == "All privileges"
? " id='grants-$i-all'>" //! uncheck all except grant if all is checked
: ">" . ($privilege == "Grant option" ? "" : script("qsl('input').onclick = function () { if (this.checked) formUncheck('grants-$i-all'); };")));
echo "<td class='center'><label class='block'>";
echo "<input type='checkbox' name=$name value='1'" .
($value ? " checked" : "") .
($allPrivileges ? " id='grants-$i-all'" : (!$grantOption ? " class='grants-$i'" : "")) .
">";
if ($allPrivileges) {
echo script("qsl('input').onclick = function () { if (this.checked) formUncheckAll('.grants-$i'); };");
} elseif (!$grantOption) {
echo script("qsl('input').onclick = function () { if (this.checked) formUncheck('grants-$i-all'); };");
}
echo "</label>";
}
$i++;
}
echo "</tr>";
}
}

View File

@@ -1,3 +1,17 @@
Adminer 4.9.3 (released 2024-10-02):
- MySQL, PostgreSQL: Fix queries splitting and string constants.
- MySQL: Fix where clause for JSON column.
- MySQL: Fix editing user's proxy privilege, refactoring.
- MariaDB: Fix comparing CURRENT_TIMESTAMP definition while altering a table.
- PostgreSQL: Fix editing record that contains a field with GENERATED ALWAYS default value.
- Fix using undefined Min_DB::info property.
- Do not include unchanged PARTITION BY definition into ALTER TABLE query.
- Do not limit unlimited memory while executing queries.
- Fix number conversion warning while reading INI settings.
- Hide invalid edit form if table record is not found.
- CSS: Fix background color of <pre> used as edit field.
- CSS: Bigger font size for code blocks.
Adminer 4.9.2 (released 2024-09-18):
- Fix textarea height for single-line inputs (used typically for SQLite text field).
- Fix undefined property in error message if driver does not support error number (e.g. PostgreSQL).