Compare commits

..

61 Commits

Author SHA1 Message Date
Jakub Vrana
b7679701ce Release 5.0.6 2025-03-17 17:13:46 +01:00
Jakub Vrana
b7258d2e95 Shorten queries saved from SQL command to URL (fix #917) 2025-03-17 15:05:56 +01:00
Jakub Vrana
c51d9919fe Update tests 2025-03-17 14:29:07 +01:00
Jakub Vrana
78c431ab20 Fix typos after 22a3efe 2025-03-17 14:28:04 +01:00
Jakub Vrana
916889bb8e Compile: Fix joining conditional echos 2025-03-17 14:25:57 +01:00
Jakub Vrana
e8b15c99f4 Add back function to get driver name (fix #919)
This reverts fe88f83.
2025-03-17 08:07:24 +01:00
Jakub Vrana
a460019535 Compile PostgreSQL: Address warnings (fix #916) 2025-03-17 07:43:10 +01:00
Jakub Vrana
ea5a7453fb CSS: Set also light color-scheme 2025-03-17 07:14:26 +01:00
Jakub Vrana
587f6a5375 CSS: Dark input fields in dark mode 2025-03-17 07:04:21 +01:00
Jakub Vrana
2bb74e7467 Compile: fetch_column() is used only internally 2025-03-17 06:38:16 +01:00
Jakub Vrana
a684044bb3 Compile SQLite: Remove server login field 2025-03-17 06:13:48 +01:00
Jakub Vrana
36a3465a64 Compile: Rename variable with other meaning in Adminer 2025-03-17 05:54:24 +01:00
Jakub Vrana
223aee70d5 Mark bugs at https://sourceforge.net/p/adminer/bugs-and-features/ 2025-03-17 05:38:14 +01:00
Jakub Vrana
c02a7d6abe Add missing namespace 2025-03-17 00:49:12 +01:00
Jakub Vrana
22a3efe4ed Code style: avoid excesive mixing of PHP and HTML 2025-03-17 00:02:41 +01:00
Jakub Vrana
dd47df9b9c Display comment in title of field 2025-03-16 22:49:50 +01:00
Jakub Vrana
0b0e8940e0 Update externals 2025-03-16 22:42:45 +01:00
Jakub Vrana
fa8339c8c2 Plugins: Remove fragile autoloader 2025-03-16 22:09:43 +01:00
Jakub Vrana
f0ee812b29 Add todo 2025-03-16 21:55:36 +01:00
Jakub Vrana
f093cb6db2 Rename file 2025-03-16 21:49:39 +01:00
Jakub Vrana
68d4a5a650 Delete adminer.version before writing (bug #855) 2025-03-16 21:43:09 +01:00
Jakub Vrana
6576fa6a73 Security: Disallow writing temporary files to symlinks (bug #855)
Cc @peterpp
2025-03-16 21:43:08 +01:00
Peter Knut
28535bf384 Refactor generating of private key
Generating of private key is atomic now.
2025-03-16 20:54:28 +01:00
Peter Knut
43e3fe375d Refactor working with a locked file 2025-03-16 20:54:24 +01:00
Jakub Vrana
d8a9a3db8d CockroachDB: Display CockroachDB instead of PostgreSQL 2025-03-16 19:07:42 +01:00
Jakub Vrana
777d5dca0e Store information about vendor 2025-03-16 19:03:12 +01:00
Jakub Vrana
6d71cd678e Separate HTML functions 2025-03-16 19:03:02 +01:00
Jakub Vrana
30714d98f9 Save bytes 2025-03-16 18:05:52 +01:00
Jakub Vrana
8353bd48de MariaDB: Display MariaDB instead of MySQL 2025-03-16 18:02:34 +01:00
Peter Knut
0762c761ac Rename functions for settings stored in a cookie 2025-03-16 17:24:28 +01:00
Jakub Vrana
529197f403 Compile: Move caching headers to file.inc.php 2025-03-16 17:16:23 +01:00
Jakub Vrana
d20cbf14e7 Remember export setting at SQL command 2025-03-16 15:13:10 +01:00
Jakub Vrana
517f63835d Plugins: add syntaxHighlighting() and CodeMirror 2025-03-16 14:00:39 +01:00
Jakub Vrana
4fee062b73 Simplify autofocus 2025-03-16 11:08:01 +01:00
Jakub Vrana
26769b2357 Do not align right non-numbers, e.g. NULL or foreign keys 2025-03-16 09:10:43 +01:00
Jakub Vrana
42bf7b9ca0 Align numbers right (bug #912) 2025-03-15 15:13:41 +01:00
Jakub Vrana
d8755c903d Save bytes 2025-03-15 13:57:29 +01:00
Jakub Vrana
a391fcb6c4 Compile: Use external PhpShrink 2025-03-15 09:38:06 +01:00
Jakub Vrana
c99ca863ce php_shrink: Move add_apo_slashes to compile.php 2025-03-15 09:10:43 +01:00
Jakub Vrana
e0283543f3 Support adminer.css + adminer-dark.css together 2025-03-15 08:51:51 +01:00
Jakub Vrana
a72e053520 php_shrink: Use foreach 2025-03-15 07:35:37 +01:00
Jakub Vrana
de654712d5 php_shrink: Preprocess ?>HTML<?php 2025-03-15 07:33:47 +01:00
Jakub Vrana
9c1d5484a2 php_shrink: Join echos interleaved with comments 2025-03-15 07:21:37 +01:00
Jakub Vrana
1fd8aa885b Fix bs,ru,sr,uk single lang version after f2ce6c0 2025-03-15 02:32:37 +01:00
Jakub Vrana
08882c6a8e Add comments to places processed by compile.php 2025-03-15 02:26:16 +01:00
Jakub Vrana
fd199ec156 php_shrink: Document bug 2025-03-15 02:26:07 +01:00
Jakub Vrana
e3515fd63f CSS: Dark mode syntax highlighting and adminer-dark.css 2025-03-15 02:00:21 +01:00
Jakub Vrana
be0a485b14 JUSH: Revert to original colors 2025-03-14 12:35:06 +01:00
Jakub Vrana
94c04712d6 SQL textarea: Open help on Ctrl+click 2025-03-14 11:01:20 +01:00
Jakub Vrana
caea0b7f68 JUSH: Use dark mode 2025-03-14 09:55:34 +01:00
Jakub Vrana
134301b3ff Tests CockroachDB: Link bug 2025-03-14 08:02:11 +01:00
Jakub Vrana
d14f3dd2d8 Tests: Check status variables 2025-03-14 07:31:57 +01:00
Jakub Vrana
67c313c86d Tests SQLite: Add more 2025-03-14 07:27:58 +01:00
Jakub Vrana
5eaa73583a Tests PostgreSQL: Materialized view 2025-03-14 06:44:02 +01:00
Jakub Vrana
68b6af6fce Tests: Check that check constraints work 2025-03-14 06:38:26 +01:00
Jakub Vrana
e65fdba5d1 Test PostgreSQL: enum 2025-03-14 06:18:42 +01:00
Jakub Vrana
8f336cd0b3 Tests: Remove useless xpath= 2025-03-14 05:58:45 +01:00
Jakub Vrana
5f3bfe8451 JUSH textarea: Use oninput 2025-03-14 05:56:30 +01:00
Jakub Vrana
1a3d58e74e Tests: Add newlines 2025-03-13 23:04:22 +01:00
Jakub Vrana
af9a851c5e Tests: generated columns 2025-03-13 23:00:14 +01:00
Jakub Vrana
3a40a855ea Develop 2025-03-13 18:29:28 +01:00
59 changed files with 1864 additions and 1822 deletions

3
.gitmodules vendored
View File

@@ -4,3 +4,6 @@
[submodule "JsShrink"]
path = externals/JsShrink
url = https://github.com/vrana/JsShrink
[submodule "PhpShrink"]
path = externals/PhpShrink
url = https://github.com/vrana/PhpShrink

View File

@@ -30,7 +30,7 @@ if ($row["auto_increment_col"]) {
}
if ($_POST) {
set_adminer_settings(array("comments" => $_POST["comments"], "defaults" => $_POST["defaults"]));
save_settings(array("comments" => $_POST["comments"], "defaults" => $_POST["defaults"]));
}
if ($_POST && !process_fields($row["fields"]) && !$error) {
@@ -180,32 +180,27 @@ foreach ($engines as $engine) {
<form action="" method="post" id="form">
<p>
<?php if (support("columns") || $TABLE == "") { ?>
<?php echo lang('Table name'); ?>: <input name="name"<?php echo ($TABLE == "" && !$_POST ? " autofocus" : ""); ?> data-maxlength="64" value="<?php echo h($row["name"]); ?>" autocapitalize="off">
<?php echo ($engines ? html_select("Engine", array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . on_help("getTarget(event).value", 1) . script("qsl('select').onchange = helpClose;") : ""); ?>
<?php
<?php
if (support("columns") || $TABLE == "") {
echo lang('Table name') . "<input name='name'" . ($TABLE == "" && !$_POST ? " autofocus" : "") . " data-maxlength='64' value='" . h($row["name"]) . "' autocapitalize='off'>\n";
echo ($engines ? html_select("Engine", array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . on_help("getTarget(event).value", 1) . script("qsl('select').onchange = helpClose;") . "\n" : "");
if ($collations) {
echo "<datalist id='collations'>" . optionlist($collations) . "</datalist>";
echo (preg_match("~sqlite|mssql~", JUSH) ? "" : "<input list='collations' name='Collation' value='" . h($row["Collation"]) . "' placeholder='(" . lang('collation') . ")'>");
}
?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php } ?>
echo "<input type='submit' value='" . lang('Save') . "'>\n";
}
<?php if (support("columns")) { ?>
<div class="scrollable">
<table id="edit-fields" class="nowrap">
<?php
if (support("columns")) {
echo "<div class='scrollable'>\n";
echo "<table id='edit-fields' class='nowrap'>\n";
edit_fields($row["fields"], $collations, "TABLE", $foreign_keys);
?>
</table>
<?php echo script("editFields();"); ?>
</div>
<p>
<?php echo lang('Auto Increment'); ?>: <input type="number" name="Auto_increment" class="size" value="<?php echo h($row["Auto_increment"]); ?>">
<?php echo checkbox("defaults", 1, ($_POST ? $_POST["defaults"] : adminer_setting("defaults")), lang('Default values'), "columnShow(this.checked, 5)", "jsonly"); ?>
<?php
$comments = ($_POST ? $_POST["comments"] : adminer_setting("comments"));
echo "</table>\n";
echo script("editFields();");
echo "</div>\n<p>\n";
echo lang('Auto Increment') . ": <input type='number' name='Auto_increment' class='size' value='" . h($row["Auto_increment"]) . "'>\n";
echo checkbox("defaults", 1, ($_POST ? $_POST["defaults"] : get_setting("defaults")), lang('Default values'), "columnShow(this.checked, 5)", "jsonly");
$comments = ($_POST ? $_POST["comments"] : get_setting("comments"));
echo (support("comment")
? checkbox("comments", 1, $comments, lang('Comment'), "editingCommentsClick(this, true);", "jsonly")
. ' ' . (preg_match('~\n~', $row["Comment"])
@@ -226,24 +221,18 @@ foreach ($engines as $engine) {
if (support("partitioning")) {
$partition_table = preg_match('~RANGE|LIST~', $row["partition_by"]);
print_fieldset("partition", lang('Partition by'), $row["partition_by"]);
?>
<p>
<?php echo html_select("partition_by", array("" => "") + $partition_by, $row["partition_by"]) . on_help("getTarget(event).value.replace(/./, 'PARTITION BY \$&')", 1) . script("qsl('select').onchange = partitionByChange;"); ?>
(<input name="partition" value="<?php echo h($row["partition"]); ?>">)
<?php echo lang('Partitions'); ?>: <input type="number" name="partitions" class="size<?php echo ($partition_table || !$row["partition_by"] ? " hidden" : ""); ?>" value="<?php echo h($row["partitions"]); ?>">
<table id="partition-table"<?php echo ($partition_table ? "" : " class='hidden'"); ?>>
<thead><tr><th><?php echo lang('Partition name'); ?><th><?php echo lang('Values'); ?></thead>
<?php
echo "<p>" . html_select("partition_by", array("" => "") + $partition_by, $row["partition_by"]) . on_help("getTarget(event).value.replace(/./, 'PARTITION BY \$&')", 1) . script("qsl('select').onchange = partitionByChange;");
echo "(<input name='partition' value='" . h($row["partition"]) . "'>)\n";
echo lang('Partitions') . ": <input type='number' name='partitions' class='size" . ($partition_table || !$row["partition_by"] ? " hidden" : "") . "' value='" . h($row["partitions"]) . "'>\n";
echo "<table id='partition-table'" . ($partition_table ? "" : " class='hidden'") . ">\n";
echo "<thead><tr><th>" . lang('Partition name') . "<th>" . lang('Values') . "</thead>\n";
foreach ($row["partition_names"] as $key => $val) {
echo '<tr>';
echo '<td><input name="partition_names[]" value="' . h($val) . '" autocapitalize="off">';
echo ($key == count($row["partition_names"]) - 1 ? script("qsl('input').oninput = partitionNameChange;") : '');
echo '<td><input name="partition_values[]" value="' . h($row["partition_values"][$key]) . '">';
}
?>
</table>
</div></fieldset>
<?php
echo "</table>\n</div></fieldset>\n";
}
?>
<input type="hidden" name="token" value="<?php echo $token; ?>">

View File

@@ -3,8 +3,13 @@ function adminer_object() {
include_once "../plugins/plugin.php";
include_once "../plugins/designs.php";
$designs = array();
foreach (glob("../designs/*", GLOB_ONLYDIR) as $filename) {
$designs["$filename/adminer.css"] = basename($filename);
foreach (glob("../designs/*", GLOB_ONLYDIR) as $dirname) {
foreach (array("", "-dark") as $mode) {
$filename = "$dirname/adminer$mode.css";
if (file_exists($filename)) {
$designs[$filename] = basename($dirname);
}
}
}
return new AdminerPlugin(array(
new AdminerDesigns($designs),

View File

@@ -1,7 +1,7 @@
<?php
namespace Adminer;
$drivers = array("server" => "MySQL") + $drivers;
$drivers = array("server" => "MySQL / MariaDB") + $drivers;
if (!defined('Adminer\DRIVER')) {
define('Adminer\DRIVER', "server"); // server - backwards compatibility
@@ -435,11 +435,13 @@ if (!defined('Adminer\DRIVER')) {
* @return mixed Db or string for error
*/
function connect($credentials) {
global $drivers;
$connection = new Db;
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
$connection->set_charset(charset($connection)); // available in MySQLi since PHP 5.0.5
$connection->set_charset(charset($connection));
$connection->query("SET sql_quote_show_create = 1, autocommit = 1");
$connection->maria = preg_match('~MariaDB~', $connection->server_info);
$drivers[DRIVER] = ($connection->maria ? "MariaDB" : "MySQL");
return $connection;
}
$return = $connection->error;

View File

@@ -321,6 +321,7 @@ if (isset($_GET["pgsql"])) {
}
function connect($credentials) {
global $drivers;
$connection = new Db;
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
if (min_version(9, 0, $connection)) {
@@ -328,6 +329,10 @@ if (isset($_GET["pgsql"])) {
}
$crdb_version = $connection->result("SHOW crdb_version");
$connection->server_info .= ($crdb_version ? "-" . preg_replace('~ \(.*~', '', $crdb_version) : "");
$connection->cockroach = preg_match('~CockroachDB~', $connection->server_info);
if ($connection->cockroach) { // we don't use "PostgreSQL / CockroachDB" by default because it's too long
$drivers[DRIVER] = "CockroachDB";
}
return $connection;
}
return $connection->error;
@@ -954,10 +959,10 @@ AND typelem = 0"
function support($feature) {
global $connection;
return ($feature == "processlist"
? !preg_match('~CockroachDB~', $connection->server_info) // https://github.com/cockroachdb/cockroach/issues/24745
: preg_match('~^(check|database|table|columns|sql|indexes|descidx|comment|view|' . (min_version(9.3) ? 'materializedview|' : '') . 'scheme|routine|sequence|trigger|type|variables|drop_col|kill|dump)$~', $feature)
);
return preg_match('~^(check|database|table|columns|sql|indexes|descidx|comment|view|' . (min_version(9.3) ? 'materializedview|' : '') . 'scheme|routine|sequence|trigger|type|variables|drop_col'
. ($connection->cockroach ? '' : '|processlist') // https://github.com/cockroachdb/cockroach/issues/24745
. '|kill|dump)$~', $feature)
;
}
function kill_process($val) {

View File

@@ -4,11 +4,10 @@ namespace Adminer;
$TABLE = $_GET["dump"];
if ($_POST && !$error) {
$cookie = "";
foreach (array("output", "format", "db_style", "types", "routines", "events", "table_style", "auto_increment", "triggers", "data_style") as $key) {
$cookie .= "&$key=" . urlencode($_POST[$key]);
}
cookie("adminer_export", substr($cookie, 1));
save_settings(
array_intersect_key($_POST, array_flip(array("output", "format", "db_style", "types", "routines", "events", "table_style", "auto_increment", "triggers", "data_style"))),
"adminer_export"
);
$tables = array_flip((array) $_POST["tables"]) + array_flip((array) $_POST["data"]);
$ext = dump_headers(
(count($tables) == 1 ? key($tables) : DB),
@@ -156,7 +155,7 @@ $data_style = array('', 'TRUNCATE+INSERT', 'INSERT');
if (JUSH == "sql") { //! use insertUpdate() in all drivers
$data_style[] = 'INSERT+UPDATE';
}
parse_str($_COOKIE["adminer_export"], $row);
$row = get_settings("adminer_export");
if (!$row) {
$row = array("output" => "text", "format" => "sql", "db_style" => (DB != "" ? "" : "CREATE"), "table_style" => "DROP+CREATE", "data_style" => "INSERT");
}

View File

@@ -1,7 +1,15 @@
<?php
namespace Adminer;
// caching headers added in compile.php
if (substr($VERSION, -4) != '-dev') {
if ($_SERVER["HTTP_IF_MODIFIED_SINCE"]) {
header("HTTP/1.1 304 Not Modified");
exit;
}
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 365*24*60*60) . " GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: immutable");
}
if ($_GET["file"] == "favicon.ico") {
header("Content-Type: image/x-icon");
@@ -11,7 +19,7 @@ if ($_GET["file"] == "favicon.ico") {
echo lzw_decompress(compile_file('../adminer/static/default.css;../externals/jush/jush.css', 'minify_css'));
} elseif ($_GET["file"] == "dark.css") {
header("Content-Type: text/css; charset=utf-8");
echo lzw_decompress(compile_file('../adminer/static/dark.css', 'minify_css'));
echo lzw_decompress(compile_file('../adminer/static/dark.css;../externals/jush/jush-dark.css', 'minify_css'));
} elseif ($_GET["file"] == "functions.js") {
header("Content-Type: text/javascript; charset=utf-8");
echo lzw_decompress(compile_file('../adminer/static/functions.js;static/editing.js', 'minify_js'));

View File

@@ -94,12 +94,13 @@ class Adminer {
}
/** Print HTML code inside <head>
* @return bool true to link favicon.ico and adminer.css if exists
* @param bool dark CSS: false to disable, true to force, null to base on user preferences
* @return bool true to link favicon.ico
*/
function head() {
?>
<link rel="stylesheet" href="../externals/jush/jush.css">
<?php
function head($dark = null) {
// this is matched by compile.php
echo "<link rel='stylesheet' href='../externals/jush/jush.css'>\n";
echo ($dark !== false ? "<link rel='stylesheet'" . ($dark ? "" : " media='(prefers-color-scheme: dark)'") . " href='../externals/jush/jush-dark.css'>\n" : "");
return true;
}
@@ -108,9 +109,11 @@ class Adminer {
*/
function css() {
$return = array();
$filename = "adminer.css";
if (file_exists($filename)) {
$return[] = "$filename?v=" . crc32(file_get_contents($filename));
foreach (array("", "-dark") as $mode) {
$filename = "adminer$mode.css";
if (file_exists($filename)) {
$return[] = "$filename?v=" . crc32(file_get_contents($filename));
}
}
return $return;
}
@@ -121,8 +124,10 @@ class Adminer {
function loginForm() {
global $drivers;
echo "<table class='layout'>\n";
// this is matched by compile.php
echo $this->loginFormField('driver', '<tr><th>' . lang('System') . '<td>', html_select("auth[driver]", $drivers, DRIVER, "loginDriver(this);"));
echo $this->loginFormField('server', '<tr><th>' . lang('Server') . '<td>', '<input name="auth[server]" value="' . h(SERVER) . '" title="hostname[:port]" placeholder="localhost" autocapitalize="off">');
// this is matched by compile.php
echo $this->loginFormField('username', '<tr><th>' . lang('Username') . '<td>', '<input name="auth[username]" id="username" autofocus value="' . h($_GET["username"]) . '" autocomplete="username" autocapitalize="off">' . script("qs('#username').form['auth[driver]'].onchange();"));
echo $this->loginFormField('password', '<tr><th>' . lang('Password') . '<td>', '<input type="password" name="auth[password]" autocomplete="current-password">');
echo $this->loginFormField('db', '<tr><th>' . lang('Database') . '<td>', '<input name="auth[db]" value="' . h($_GET["db"]) . '" autocapitalize="off">');
@@ -167,7 +172,7 @@ class Adminer {
* @return string HTML code, "" to ignore field
*/
function fieldName($field, $order = 0) {
return '<span title="' . h($field["full_type"]) . '">' . h($field["field"]) . '</span>';
return '<span title="' . h($field["full_type"] . ($field["comment"] != "" ? " : $field[comment]" : '')) . '">' . h($field["field"]) . '</span>';
}
/** Print links after select heading
@@ -988,16 +993,18 @@ class Adminer {
</span>
</h1>
<?php
// this is matched by compile.php
switch_lang();
if ($missing == "auth") {
$output = "";
foreach ((array) $_SESSION["pwds"] as $vendor => $servers) {
foreach ($servers as $server => $usernames) {
$name = h(get_setting("vendor-$server") ?: $drivers[$vendor]);
foreach ($usernames as $username => $password) {
if ($password !== null) {
$dbs = $_SESSION["db"][$vendor][$server][$username];
foreach (($dbs ? array_keys($dbs) : array("")) as $db) {
$output .= "<li><a href='" . h(auth_url($vendor, $server, $username, $db)) . "'>($drivers[$vendor]) " . h($username . ($server != "" ? "@" . $this->serverName($server) : "") . ($db != "" ? " - $db" : "")) . "</a>\n";
$output .= "<li><a href='" . h(auth_url($vendor, $server, $username, $db)) . "'>($name) " . h($username . ($server != "" ? "@" . $this->serverName($server) : "") . ($db != "" ? " - $db" : "")) . "</a>\n";
}
}
}
@@ -1012,30 +1019,7 @@ class Adminer {
$connection->select_db(DB);
$tables = table_status('', true);
}
echo script_src("../externals/jush/modules/jush.js");
echo script_src("../externals/jush/modules/jush-textarea.js");
echo script_src("../externals/jush/modules/jush-txt.js");
echo script_src("../externals/jush/modules/jush-js.js");
if (support("sql")) {
echo script_src("../externals/jush/modules/jush-" . JUSH . ".js");
?>
<script<?php echo nonce(); ?>>
<?php
if ($tables) {
$links = array();
foreach ($tables as $table => $type) {
$links[] = preg_quote($table, '/');
}
echo "var jushLinks = { " . JUSH . ": [ '" . js_escape(ME) . (support("table") ? "table=" : "select=") . "\$&', /\\b(" . implode("|", $links) . ")\\b/g ] };\n";
foreach (array("bac", "bra", "sqlite_quo", "mssql_bra") as $val) {
echo "jushLinks.$val = jushLinks." . JUSH . ";\n";
}
}
?>
bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '\1', $connection->server_info) : ""); ?>'<?php echo ($connection->maria ? ", true" : ""); ?>);
</script>
<?php
}
$this->syntaxHighlighting($tables);
$this->databasesPrint($missing);
$actions = array();
if (DB == "" || !$missing) {
@@ -1060,6 +1044,34 @@ bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '
}
}
/** Set up syntax highlight for code and <textarea>
* @param array result of table_status()
*/
function syntaxHighlighting($tables) {
global $connection;
// this is matched by compile.php
echo script_src("../externals/jush/modules/jush.js");
echo script_src("../externals/jush/modules/jush-textarea.js");
echo script_src("../externals/jush/modules/jush-txt.js");
echo script_src("../externals/jush/modules/jush-js.js");
if (support("sql")) {
echo script_src("../externals/jush/modules/jush-" . JUSH . ".js");
echo "<script" . nonce() . ">\n";
if ($tables) {
$links = array();
foreach ($tables as $table => $type) {
$links[] = preg_quote($table, '/');
}
echo "var jushLinks = { " . JUSH . ": [ '" . js_escape(ME) . (support("table") ? "table=" : "select=") . "\$&', /\\b(" . implode("|", $links) . ")\\b/g ] };\n";
foreach (array("bac", "bra", "sqlite_quo", "mssql_bra") as $val) {
echo "jushLinks.$val = jushLinks." . JUSH . ";\n";
}
}
echo "</script>\n";
}
echo script("bodyLoad('" . (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '\1', $connection->server_info) : "") . "'" . ($connection->maria ? ", true" : "") . ");");
}
/** Prints databases list in menu
* @param string
* @return null

View File

@@ -19,7 +19,17 @@ if ($_COOKIE["adminer_permanent"]) {
function add_invalid_login() {
global $adminer;
$fp = file_open_lock(get_temp_dir() . "/adminer.invalid");
$base = get_temp_dir() . "/adminer.invalid";
// adminer.invalid may not be writable by us, try the files with random suffixes
foreach (glob("$base*") ?: array($base) as $filename) {
$fp = file_open_lock($filename);
if ($fp) {
break;
}
}
if (!$fp) {
$fp = file_open_lock("$base-" . rand_string());
}
if (!$fp) {
return;
}
@@ -42,7 +52,15 @@ function add_invalid_login() {
function check_invalid_login() {
global $adminer;
$invalids = unserialize(@file_get_contents(get_temp_dir() . "/adminer.invalid")); // @ - may not exist
$invalids = array();
foreach (glob(get_temp_dir() . "/adminer.invalid*") as $filename) {
$fp = file_open_lock($filename);
if ($fp) {
$invalids = unserialize(stream_get_contents($fp));
file_unlock($fp);
break;
}
}
$invalid = ($invalids ? $invalids[$adminer->bruteForceKey()] : array());
$next_attempt = ($invalid[1] > 29 ? $invalid[0] - time() : 0); // allow 30 invalid attempts
if ($next_attempt > 0) { //! do the same with permanent login
@@ -61,7 +79,7 @@ if ($auth) {
set_password($vendor, $server, $username, $password);
$_SESSION["db"][$vendor][$server][$username][$db] = true;
if ($auth["permanent"]) {
$key = base64_encode($vendor) . "-" . base64_encode($server) . "-" . base64_encode($username) . "-" . base64_encode($db);
$key = implode("-", array_map('base64_encode', array($vendor, $server, $username, $db)));
$private = $adminer->permanentLogin(true);
$permanent[$key] = "$key:" . base64_encode($private ? encrypt_string($password, $private) : "");
cookie("adminer_permanent", implode(" ", $permanent));
@@ -169,6 +187,9 @@ if (isset($_GET["username"]) && is_string(get_password())) {
if ($adminer->operators === null) {
$adminer->operators = $driver->operators;
}
if (isset($connection->maria) || $connection->cockroach) {
save_settings(array("vendor-" . SERVER => $drivers[DRIVER]));
}
}
}

View File

@@ -3,6 +3,7 @@ namespace Adminer;
include "../adminer/include/version.inc.php";
include "../adminer/include/errors.inc.php";
// this is matched by compile.php
include "../adminer/include/coverage.inc.php";
// disable filter.default
@@ -21,6 +22,7 @@ if (function_exists("mb_internal_encoding")) {
}
include "../adminer/include/functions.inc.php";
include "../adminer/include/html.inc.php";
// used only in compiled file
if (isset($_GET["file"])) {
@@ -28,7 +30,9 @@ if (isset($_GET["file"])) {
}
if ($_GET["script"] == "version") {
$fp = file_open_lock(get_temp_dir() . "/adminer.version");
$filename = get_temp_dir() . "/adminer.version";
unlink($filename); // it may not be writable by us
$fp = file_open_lock($filename);
if ($fp) {
file_write_unlock($fp, serialize(array("signature" => $_POST["signature"], "version" => $_POST["version"])));
}
@@ -74,6 +78,7 @@ include "../adminer/drivers/oracle.inc.php";
include "../adminer/drivers/mssql.inc.php";
include "./include/adminer.inc.php";
$adminer = (function_exists('adminer_object') ? adminer_object() : new Adminer);
// this is matched by compile.php
include "../adminer/drivers/mysql.inc.php"; // must be included as last driver
define('Adminer\JUSH', Driver::$jush);

View File

@@ -2,9 +2,9 @@
namespace Adminer;
// coverage is used in tests and removed in compilation
if (extension_loaded("xdebug") && file_exists(sys_get_temp_dir() . "/adminer_coverage.ser")) {
if (extension_loaded("xdebug") && file_exists(sys_get_temp_dir() . "/adminer.coverage")) {
function save_coverage() {
$coverage_filename = sys_get_temp_dir() . "/adminer_coverage.ser";
$coverage_filename = sys_get_temp_dir() . "/adminer.coverage";
$coverage = unserialize(file_get_contents($coverage_filename));
foreach (xdebug_get_code_coverage() as $filename => $lines) {
foreach ($lines as $l => $val) {

View File

@@ -31,23 +31,22 @@ function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") {
<link rel="stylesheet" href="../adminer/static/default.css">
<?php
$css = $adminer->css();
if ($css) {
foreach ($css as $val) {
echo "<link rel='stylesheet' href='" . h($val) . "'>\n";
}
} else {
echo "<link rel='stylesheet' media='(prefers-color-scheme: dark)' href='../adminer/static/dark.css'>\n";
$dark = (count($css) == 1 ? !!preg_match('~-dark~', $css[0]) : null);
if ($dark !== false) {
echo "<link rel='stylesheet'" . ($dark ? "" : " media='(prefers-color-scheme: dark)'") . " href='../adminer/static/dark.css'>\n";
}
echo "<meta name='color-scheme' content='" . ($dark === null ? "light dark" : ($dark ? "dark" : "light")) . "'>\n";
// this is matched by compile.php
echo script_src("../adminer/static/functions.js");
echo script_src("static/editing.js");
?>
<?php if ($adminer->head()) { ?>
<link rel="shortcut icon" type="image/x-icon" href="../adminer/static/favicon.ico">
<link rel="apple-touch-icon" href="../adminer/static/favicon.ico">
<?php } ?>
<body class="<?php echo lang('ltr'); ?> nojs">
<?php
if ($adminer->head($dark)) {
echo "<link rel='shortcut icon' type='image/x-icon' href='../adminer/static/favicon.ico'>\n";
echo "<link rel='apple-touch-icon' href='../adminer/static/favicon.ico'>\n";
}
foreach ($css as $val) {
echo "<link rel='stylesheet'" . (preg_match('~-dark~', $val) && !$dark ? " media='(prefers-color-scheme: dark)'" : "") . " href='" . h($val) . "'>\n";
}
echo "\n<body class='" . lang('ltr') . " nojs'>\n";
$filename = get_temp_dir() . "/adminer.version";
if (!$_COOKIE["adminer_version"] && function_exists('openssl_verify') && file_exists($filename) && filemtime($filename) + 86400 > time()) { // 86400 - 1 day in seconds
$version = unserialize(file_get_contents($filename));
@@ -65,21 +64,16 @@ fQIDAQAB
$_COOKIE["adminer_version"] = $version["version"]; // doesn't need to send to the browser
}
}
?>
<script<?php echo nonce(); ?>>
mixin(document.body, {onkeydown: bodyKeydown, onclick: bodyClick<?php
echo (isset($_COOKIE["adminer_version"]) ? "" : ", onload: partial(verifyVersion, '$VERSION', '" . js_escape(ME) . "', '" . get_token() . "')"); // $token may be empty in auth.inc.php
?>});
echo script("mixin(document.body, {onkeydown: bodyKeydown, onclick: bodyClick"
. (isset($_COOKIE["adminer_version"]) ? "" : ", onload: partial(verifyVersion, '$VERSION', '" . js_escape(ME) . "', '" . get_token() . "')") // $token may be empty in auth.inc.php
. "});
document.body.className = document.body.className.replace(/ nojs/, ' js');
var offlineMessage = '<?php echo js_escape(lang('You are offline.')); ?>';
var thousandsSeparator = '<?php echo js_escape(lang(',')); ?>';
</script>
<div id="help" class="jush-<?php echo JUSH; ?> jsonly hidden"></div>
<?php echo script("mixin(qs('#help'), {onmouseover: function () { helpOpen = 1; }, onmouseout: helpMouseout});"); ?>
<div id="content">
<?php
var offlineMessage = '" . js_escape(lang('You are offline.')) . "';
var thousandsSeparator = '" . js_escape(lang(',')) . "';")
;
echo "<div id='help' class='jush-" . JUSH . " jsonly hidden'></div>\n";
echo script("mixin(qs('#help'), {onmouseover: function () { helpOpen = 1; }, onmouseout: helpMouseout});");
echo "<div id='content'>\n";
if ($breadcrumb !== null) {
$link = substr(preg_replace('~\b(username|db|ns)=[^&]*&~', '', ME), 0, -1);
echo '<p id="breadcrumb"><a href="' . h($link ?: ".") . '">' . $drivers[DRIVER] . '</a> » ';

View File

@@ -13,12 +13,13 @@ function add_driver($id, $name) {
$drivers[$id] = $name;
}
/** Get driver
* @return Driver
/** Get driver name
* @param string
* @return string
*/
function get_driver() {
global $driver;
return $driver;
function get_driver($id) {
global $drivers;
return $drivers[$id];
}
abstract class SqlDriver {

View File

@@ -90,7 +90,8 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
if ($link) {
$val = "<a href='" . h($link) . "'" . (is_url($link) ? target_blank() : '') . ">$val</a>";
}
echo "<td>$val";
// https://dev.mysql.com/doc/dev/mysql-server/latest/field__types_8h.html
echo "<td" . ($types[$key] <= 9 || $types[$key] == 246 ? " class='number'" : "") . ">$val";
}
}
echo ($i ? "</table>\n</div>" : "<p class='message'>" . lang('No rows.')) . "\n";
@@ -119,31 +120,6 @@ function referencable_primary($self) {
return $return;
}
/** Get settings stored in a cookie
* @return array
*/
function adminer_settings() {
parse_str($_COOKIE["adminer_settings"], $settings);
return $settings;
}
/** Get setting stored in a cookie
* @param string
* @return array
*/
function adminer_setting($key) {
$settings = adminer_settings();
return $settings[$key];
}
/** Store settings to a cookie
* @param array
* @return bool
*/
function set_adminer_settings($settings) {
return cookie("adminer_settings", http_build_query($settings + adminer_settings()));
}
/** Print SQL <textarea> tag
* @param string
* @param string or array in which case [0] of every element is used
@@ -209,7 +185,7 @@ function json_row($key, $val = null) {
function edit_type($key, $field, $collations, $foreign_keys = array(), $extra_types = array()) {
global $driver;
$type = $field["type"];
?><td><select name="<?php echo h($key); ?>[type]" class="type" aria-labelledby="label-type"><?php
echo "<td><select name='" . h($key) . "[type]' class='type' aria-labelledby='label-type'>";
if ($type && !array_key_exists($type, $driver->types()) && !isset($foreign_keys[$type]) && !in_array($type, $extra_types)) {
$extra_types[] = $type;
}
@@ -218,12 +194,11 @@ function edit_type($key, $field, $collations, $foreign_keys = array(), $extra_ty
$structured_types[lang('Foreign keys')] = $foreign_keys;
}
echo optionlist(array_merge($extra_types, $structured_types), $type);
?></select><td><input
name="<?php echo h($key); ?>[length]"
value="<?php echo h($field["length"]); ?>"
size="3"
<?php echo (!$field["length"] && preg_match('~var(char|binary)$~', $type) ? " class='required'" : ""); //! type="number" with enabled JavaScript ?>
aria-labelledby="label-length"><td class="options"><?php
echo "</select><td>";
echo "<input name='" . h($key) . "[length]' value='" . h($field["length"]) . "' size='3'"
. (!$field["length"] && preg_match('~var(char|binary)$~', $type) ? " class='required'" : "") //! type="number" with enabled JavaScript
. " aria-labelledby='label-length'>";
echo "<td class='options'>";
echo ($collations
? "<input list='collations' name='" . h($key) . "[collation]'" . (preg_match('~(char|text|enum|set)$~', $type) ? "" : " class='hidden'") . " value='" . h($field["collation"]) . "' placeholder='(" . lang('collation') . ")'>"
: ''
@@ -349,54 +324,51 @@ function type_class($type) {
function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = array()) {
global $driver;
$fields = array_values($fields);
$default_class = (($_POST ? $_POST["defaults"] : adminer_setting("defaults")) ? "" : " class='hidden'");
$comment_class = (($_POST ? $_POST["comments"] : adminer_setting("comments")) ? "" : " class='hidden'");
$default_class = (($_POST ? $_POST["defaults"] : get_setting("defaults")) ? "" : " class='hidden'");
$comment_class = (($_POST ? $_POST["comments"] : get_setting("comments")) ? "" : " class='hidden'");
?>
<thead><tr>
<?php echo ($type == "PROCEDURE" ? "<td>" : ""); ?>
<th id="label-name"><?php echo ($type == "TABLE" ? lang('Column name') : lang('Parameter name')); ?>
<td id="label-type"><?php echo lang('Type'); ?><textarea id="enum-edit" rows="4" cols="12" wrap="off" style="display: none;"></textarea><?php echo script("qs('#enum-edit').onblur = editingLengthBlur;"); ?>
<td id="label-length"><?php echo lang('Length'); ?>
<td><?php echo lang('Options'); /* no label required, options have their own label */ ?>
<?php if ($type == "TABLE") { ?>
<td id="label-null">NULL
<td><input type="radio" name="auto_increment_col" value=""><abbr id="label-ai" title="<?php echo lang('Auto Increment'); ?>">AI</abbr><?php echo doc_link(array(
'sql' => "example-auto-increment.html",
'mariadb' => "auto_increment/",
'sqlite' => "autoinc.html",
'pgsql' => "datatype-numeric.html#DATATYPE-SERIAL",
'mssql' => "t-sql/statements/create-table-transact-sql-identity-property",
)); ?>
<td id="label-default"<?php echo $default_class; ?>><?php echo lang('Default value'); ?>
<?php echo (support("comment") ? "<td id='label-comment'$comment_class>" . lang('Comment') : ""); ?>
<?php } ?>
<td><?php echo "<input type='image' class='icon' name='add[" . (support("move_col") ? 0 : count($fields)) . "]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'>" . script("row_count = " . count($fields) . ";"); ?>
</thead>
<tbody>
<?php
<td><?php
echo lang('Options'); // no label required, options have their own label
if ($type == "TABLE") {
echo "<td id='label-null'>NULL\n";
echo "<td><input type='radio' name='auto_increment_col' value=''><abbr id='label-ai' title='" . lang('Auto Increment') . "'>AI</abbr>";
echo doc_link(array(
'sql' => "example-auto-increment.html",
'mariadb' => "auto_increment/",
'sqlite' => "autoinc.html",
'pgsql' => "datatype-numeric.html#DATATYPE-SERIAL",
'mssql' => "t-sql/statements/create-table-transact-sql-identity-property",
));
echo "<td id='label-default'$default_class>" . lang('Default value');
echo (support("comment") ? "<td id='label-comment'$comment_class>" . lang('Comment') : "");
}
echo "<td><input type='image' class='icon' name='add[" . (support("move_col") ? 0 : count($fields)) . "]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'>" . script("row_count = " . count($fields) . ";");
echo "</thead>\n<tbody>\n";
echo script("mixin(qsl('tbody'), {onclick: editingClick, onkeydown: editingKeydown, oninput: editingInput});");
foreach ($fields as $i => $field) {
$i++;
$orig = $field[($_POST ? "orig" : "field")];
$display = (isset($_POST["add"][$i-1]) || (isset($field["field"]) && !$_POST["drop_col"][$i])) && (support("drop_col") || $orig == "");
?>
<tr<?php echo ($display ? "" : " style='display: none;'"); ?>>
<?php echo ($type == "PROCEDURE" ? "<td>" . html_select("fields[$i][inout]", explode("|", $driver->inout), $field["inout"]) : "") . "<th>"; ?>
<?php if ($display) { ?>
<input name="fields[<?php echo $i; ?>][field]" value="<?php echo h($field["field"]); ?>" data-maxlength="64" autocapitalize="off" aria-labelledby="label-name">
<?php } ?>
<input type="hidden" name="fields[<?php echo $i; ?>][orig]" value="<?php echo h($orig); ?>"><?php edit_type("fields[$i]", $field, $collations, $foreign_keys); ?>
<?php
echo "<tr" . ($display ? "" : " style='display: none;'") . ">\n";
echo ($type == "PROCEDURE" ? "<td>" . html_select("fields[$i][inout]", explode("|", $driver->inout), $field["inout"]) : "") . "<th>";
if ($display) {
echo "<input name='fields[$i][field]' value='" . h($field["field"]) . "' data-maxlength='64' autocapitalize='off' aria-labelledby='label-name'>\n";
}
echo "<input type='hidden' name='fields[$i][orig]' value='" . h($orig) . "'>";
edit_type("fields[$i]", $field, $collations, $foreign_keys);
if ($type == "TABLE") {
?>
<td><?php echo checkbox("fields[$i][null]", 1, $field["null"], "", "", "block", "label-null"); ?>
<td><label class="block"><input type="radio" name="auto_increment_col" value="<?php echo $i; ?>"<?php echo ($field["auto_increment"] ? " checked" : ""); ?> aria-labelledby="label-ai"></label><td<?php echo $default_class; ?>><?php
echo ($driver->generated
echo "<td>" . checkbox("fields[$i][null]", 1, $field["null"], "", "", "block", "label-null");
echo "<td><label class='block'><input type='radio' name='auto_increment_col' value='$i'" . ($field["auto_increment"] ? " checked" : "") . " aria-labelledby='label-ai'></label>";
echo "<td$default_class>" . ($driver->generated
? html_select("fields[$i][generated]", array_merge(array("", "DEFAULT"), $driver->generated), $field["generated"]) . " "
: checkbox("fields[$i][generated]", 1, $field["generated"], "", "", "", "label-default")
);
?>
<input name="fields[<?php echo $i; ?>][default]" value="<?php echo h($field["default"]); ?>" aria-labelledby="label-default"><?php
echo "<input name='fields[$i][default]' value='" . h($field["default"]) . "' aria-labelledby='label-default'>";
echo (support("comment") ? "<td$comment_class><input name='fields[$i][comment]' value='" . h($field["comment"]) . "' data-maxlength='" . (min_version(5.5) ? 1024 : 255) . "' aria-labelledby='label-comment'>" : "");
}
echo "<td>";

View File

@@ -20,6 +20,14 @@ function adminer() {
return $adminer;
}
/** Get Driver object
* @return Driver
*/
function driver() {
global $driver;
return $driver;
}
/** Get Adminer version
* @return string
*/
@@ -40,6 +48,15 @@ function idf_unescape($idf) {
return str_replace($last . $last, $last, substr($idf, 1, -1));
}
/** Shortcut for $connection->quote($string)
* @param string
* @return string
*/
function q($string) {
global $connection;
return $connection->quote($string);
}
/** Escape string to use inside ''
* @param string
* @return string
@@ -122,171 +139,6 @@ function charset($connection) {
return (min_version("5.5.3", 0, $connection) ? "utf8mb4" : "utf8"); // SHOW CHARSET would require an extra query
}
/** Return <script> element
* @param string
* @param string
* @return string
*/
function script($source, $trailing = "\n") {
return "<script" . nonce() . ">$source</script>$trailing";
}
/** Return <script src> element
* @param string
* @return string
*/
function script_src($url) {
return "<script src='" . h($url) . "'" . nonce() . "></script>\n";
}
/** Get a nonce="" attribute with CSP nonce
* @return string
*/
function nonce() {
return ' nonce="' . get_nonce() . '"';
}
/** Get a target="_blank" attribute
* @return string
*/
function target_blank() {
return ' target="_blank" rel="noreferrer noopener"';
}
/** Escape for HTML
* @param string
* @return string
*/
function h($string) {
return str_replace("\0", "&#0;", htmlspecialchars($string, ENT_QUOTES, 'utf-8'));
}
/** Convert \n to <br>
* @param string
* @return string
*/
function nl_br($string) {
return str_replace("\n", "<br>", $string); // nl2br() uses XHTML before PHP 5.3
}
/** Generate HTML checkbox
* @param string
* @param string
* @param bool
* @param string
* @param string
* @param string
* @param string
* @return string
*/
function checkbox($name, $value, $checked, $label = "", $onclick = "", $class = "", $labelled_by = "") {
$return = "<input type='checkbox' name='$name' value='" . h($value) . "'"
. ($checked ? " checked" : "")
. ($labelled_by ? " aria-labelledby='$labelled_by'" : "")
. ">"
. ($onclick ? script("qsl('input').onclick = function () { $onclick };", "") : "")
;
return ($label != "" || $class ? "<label" . ($class ? " class='$class'" : "") . ">$return" . h($label) . "</label>" : $return);
}
/** Generate list of HTML options
* @param array array of strings or arrays (creates optgroup)
* @param mixed
* @param bool always use array keys for value="", otherwise only string keys are used
* @return string
*/
function optionlist($options, $selected = null, $use_keys = false) {
$return = "";
foreach ($options as $k => $v) {
$opts = array($k => $v);
if (is_array($v)) {
$return .= '<optgroup label="' . h($k) . '">';
$opts = $v;
}
foreach ($opts as $key => $val) {
$return .= '<option'
. ($use_keys || is_string($key) ? ' value="' . h($key) . '"' : '')
. ($selected !== null && ($use_keys || is_string($key) ? (string) $key : $val) === $selected ? ' selected' : '')
. '>' . h($val)
;
}
if (is_array($v)) {
$return .= '</optgroup>';
}
}
return $return;
}
/** Generate HTML <select>
* @param string
* @param array
* @param string
* @param string
* @param string
* @return string
*/
function html_select($name, $options, $value = "", $onchange = "", $labelled_by = "") {
return "<select name='" . h($name) . "'"
. ($labelled_by ? " aria-labelledby='$labelled_by'" : "")
. ">" . optionlist($options, $value) . "</select>"
. ($onchange ? script("qsl('select').onchange = function () { $onchange };", "") : "")
;
}
/** Generate HTML radio list
* @param string
* @param array
* @param string
* @return string
*/
function html_radios($name, $options, $value = "") {
$return = "";
foreach ($options as $key => $val) {
$return .= "<label><input type='radio' name='" . h($name) . "' value='" . h($key) . "'" . ($key == $value ? " checked" : "") . ">" . h($val) . "</label>";
}
return $return;
}
/** Get onclick confirmation
* @param string
* @param string
* @return string
*/
function confirm($message = "", $selector = "qsl('input')") {
return script("$selector.onclick = function () { return confirm('" . ($message ? js_escape($message) : lang('Are you sure?')) . "'); };", "");
}
/** Print header for hidden fieldset (close by </div></fieldset>)
* @param string
* @param string
* @param bool
* @return null
*/
function print_fieldset($id, $legend, $visible = false) {
echo "<fieldset><legend>";
echo "<a href='#fieldset-$id'>$legend</a>";
echo script("qsl('a').onclick = partial(toggle, 'fieldset-$id');", "");
echo "</legend>";
echo "<div id='fieldset-$id'" . ($visible ? "" : " class='hidden'") . ">\n";
}
/** Return class='active' if $bold is true
* @param bool
* @param string
* @return string
*/
function bold($bold, $class = "") {
return ($bold ? " class='active $class'" : ($class ? " class='$class'" : ""));
}
/** Escape string for JavaScript apostrophes
* @param string
* @return string
*/
function js_escape($string) {
return addcslashes($string, "\r\n'\\/"); // slash for <script>
}
/** Get INI boolean value
* @param string
* @return bool
@@ -335,15 +187,6 @@ function get_password() {
return $return;
}
/** Shortcut for $connection->quote($string)
* @param string
* @return string
*/
function q($string) {
global $connection;
return $connection->quote($string);
}
/** Get single value from database
* @param string
* @param int
@@ -464,8 +307,7 @@ function where($where, $fields = array()) {
. (JUSH == "sql" && $field_type == "json" ? " = CAST(" . q($val) . " AS JSON)"
: (JUSH == "sql" && is_numeric($val) && preg_match('~\.~', $val) ? " LIKE " . q($val) // LIKE because of floats but slow with ints
: (JUSH == "mssql" && strpos($field_type, "datetime") === false ? " LIKE " . q(preg_replace('~[_%[]~', '[\0]', $val)) // LIKE because of text but it does not work with datetime
: " = " . unconvert_field($fields[$key], q($val))
)))
: " = " . unconvert_field($fields[$key], q($val)))))
; //! enum and set
if (JUSH == "sql" && preg_match('~char|text~', $field_type) && preg_match("~[^ -@]~", $val)) { // not just [a-z] to catch non-ASCII characters
$return[] = "$column = " . q($val) . " COLLATE " . charset($connection) . "_bin";
@@ -537,6 +379,34 @@ function cookie($name, $value, $lifetime = 2592000) {
);
}
/** Get settings stored in a cookie
* @param string
* @return array
*/
function get_settings($cookie) {
parse_str($_COOKIE[$cookie], $settings);
return $settings;
}
/** Get setting stored in a cookie
* @param string
* @param string
* @return mixed
*/
function get_setting($key, $cookie = "adminer_settings") {
$settings = get_settings($cookie);
return $settings[$key];
}
/** Store settings to a cookie
* @param array
* @param string
* @return bool
*/
function save_settings($settings, $cookie = "adminer_settings") {
return cookie($cookie, http_build_query($settings + get_settings($cookie)));
}
/** Restart stopped session
* @return null
*/
@@ -721,18 +591,6 @@ function remove_from_uri($param = "") {
return substr(preg_replace("~(?<=[?&])($param" . (SID ? "" : "|" . session_name()) . ")=[^&]*&~", '', relative_uri() . "&"), 0, -1);
}
/** Generate page number for pagination
* @param int
* @param int
* @return string
*/
function pagination($page, $current) {
return " " . ($page == $current
? $page + 1
: '<a href="' . h(remove_from_uri("page") . ($page ? "&page=$page" . ($_GET["next"] ? "&next=" . urlencode($_GET["next"]) : "") : "")) . '">' . ($page + 1) . "</a>"
);
}
/** Get file contents from $_FILES
* @param string
* @param bool
@@ -833,36 +691,6 @@ function friendly_url($val) {
return preg_replace('~\W~i', '-', $val);
}
/** Print hidden fields
* @param array
* @param array
* @param string
* @return bool
*/
function hidden_fields($process, $ignore = array(), $prefix = '') {
$return = false;
foreach ($process as $key => $val) {
if (!in_array($key, $ignore)) {
if (is_array($val)) {
hidden_fields($val, array(), $key);
} else {
$return = true;
echo '<input type="hidden" name="' . h($prefix ? $prefix . "[$key]" : $key) . '" value="' . h($val) . '">';
}
}
}
return $return;
}
/** Print hidden fields for GET forms
* @return null
*/
function hidden_fields_get() {
echo (sid() ? '<input type="hidden" name="' . session_name() . '" value="' . h(session_id()) . '">' : '');
echo (SERVER !== null ? '<input type="hidden" name="' . DRIVER . '" value="' . h(SERVER) . '">' : "");
echo '<input type="hidden" name="username" value="' . h($_GET["username"]) . '">';
}
/** Get status of a single table and fall back to name on error
* @param string
* @param bool
@@ -888,173 +716,6 @@ function column_foreign_keys($table) {
return $return;
}
/** Print enum input field
* @param string "radio"|"checkbox"
* @param string
* @param array
* @param mixed string|array
* @param string
* @return null
*/
function enum_input($type, $attrs, $field, $value, $empty = null) {
global $adminer;
preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
$return = ($empty !== null ? "<label><input type='$type'$attrs value='$empty'" . ((is_array($value) ? in_array($empty, $value) : $value === $empty) ? " checked" : "") . "><i>" . lang('empty') . "</i></label>" : "");
foreach ($matches[1] as $i => $val) {
$val = stripcslashes(str_replace("''", "'", $val));
$checked = (is_array($value) ? in_array($val, $value) : $value === $val);
$return .= " <label><input type='$type'$attrs value='" . h($val) . "'" . ($checked ? ' checked' : '') . '>' . h($adminer->editVal($val, $field)) . '</label>';
}
return $return;
}
/** Print edit input field
* @param array one field from fields()
* @param mixed
* @param string
* @return null
*/
function input($field, $value, $function) {
global $driver, $adminer;
$name = h(bracket_escape($field["field"]));
echo "<td class='function'>";
if (is_array($value) && !$function) {
$value = json_encode($value, 128); // 128 - JSON_PRETTY_PRINT available since PHP 5.4
$function = "json";
}
$reset = (JUSH == "mssql" && $field["auto_increment"]);
if ($reset && !$_POST["save"]) {
$function = null;
}
$functions = (isset($_GET["select"]) || $reset ? array("orig" => lang('original')) : array()) + $adminer->editFunctions($field);
$disabled = stripos($field["default"], "GENERATED ALWAYS AS ") === 0 ? " disabled=''" : "";
$attrs = " name='fields[$name]'$disabled";
$enums = $driver->enumLength($field);
if ($enums) {
$field["type"] = "enum";
$field["length"] = $enums;
}
echo $driver->unconvertFunction($field) . " ";
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]'$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))
) . '<td>';
$input = $adminer->editInput($_GET["edit"], $field, $attrs, $value); // usage in call is without a table
if ($input != "") {
echo $input;
} elseif (preg_match('~bool~', $field["type"])) {
echo "<input type='hidden'$attrs value='0'>"
. "<input type='checkbox'" . (preg_match('~^(1|t|true|y|yes|on)$~i', $value) ? " checked='checked'" : "") . "$attrs value='1'>";
} elseif ($field["type"] == "set") {
preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
foreach ($matches[1] as $i => $val) {
$val = stripcslashes(str_replace("''", "'", $val));
$checked = in_array($val, explode(",", $value), true);
echo " <label><input type='checkbox' name='fields[$name][$i]' value='" . h($val) . "'" . ($checked ? ' checked' : '') . ">" . h($adminer->editVal($val, $field)) . '</label>';
}
} elseif (preg_match('~blob|bytea|raw|file~', $field["type"]) && ini_bool("file_uploads")) {
echo "<input type='file' name='fields-$name'>";
} elseif (($text = preg_match('~text|lob|memo~i', $field["type"])) || preg_match("~\n~", $value)) {
if ($text && JUSH != "sqlite") {
$attrs .= " cols='50' rows='12'";
} else {
$rows = min(12, substr_count($value, "\n") + 1);
$attrs .= " cols='30' rows='$rows'" . ($rows == 1 ? " style='height: 1.2em;'" : ""); // 1.2em - line-height
}
echo "<textarea$attrs>" . h($value) . '</textarea>';
} elseif ($function == "json" || preg_match('~^jsonb?$~', $field["type"])) {
echo "<textarea$attrs cols='50' rows='12' class='jush-js'>" . h($value) . '</textarea>';
} else {
// int(3) is only a display hint
$types = $driver->types();
$maxlength = (!preg_match('~int~', $field["type"]) && preg_match('~^(\d+)(,(\d+))?$~', $field["length"], $match)
? ((preg_match("~binary~", $field["type"]) ? 2 : 1) * $match[1] + ($match[3] ? 1 : 0) + ($match[2] && !$field["unsigned"] ? 1 : 0))
: ($types[$field["type"]] ? $types[$field["type"]] + ($field["unsigned"] ? 0 : 1) : 0)
);
if (JUSH == 'sql' && min_version(5.6) && preg_match('~time~', $field["type"])) {
$maxlength += 7; // microtime
}
// type='date' and type='time' display localized value which may be confusing, type='datetime' uses 'T' as date and time separator
echo "<input"
. ((!$has_function || $function === "") && preg_match('~(?<!o)int(?!er)~', $field["type"]) && !preg_match('~\[\]~', $field["full_type"]) ? " type='number'" : "")
. " value='" . h($value) . "'" . ($maxlength ? " data-maxlength='$maxlength'" : "")
. (preg_match('~char|binary~', $field["type"]) && $maxlength > 20 ? " size='40'" : "")
. "$attrs>"
;
}
echo $adminer->editHint($_GET["edit"], $field, $value);
// skip 'original'
$first = 0;
foreach ($functions as $key => $val) {
if ($key === "" || !$val) {
break;
}
$first++;
}
if ($first) {
echo script("mixin(qsl('td'), {onchange: partial(skipOriginal, $first), oninput: function () { this.onchange(); }});");
}
}
}
/** Process edit input field
* @param one field from fields()
* @return string or false to leave the original value
*/
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];
if ($field["type"] == "enum" || $driver->enumLength($field)) {
if ($value == -1) {
return false;
}
if ($value == "") {
return "NULL";
}
}
if ($field["auto_increment"] && $value == "") {
return null;
}
if ($function == "orig") {
return (preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"]) ? idf_escape($field["field"]) : false);
}
if ($function == "NULL") {
return "NULL";
}
if ($field["type"] == "set") {
$value = implode(",", (array) $value);
}
if ($function == "json") {
$function = "";
$value = json_decode($value, true);
if (!is_array($value)) {
return false; //! report errors
}
return $value;
}
if (preg_match('~blob|bytea|raw|file~', $field["type"]) && ini_bool("file_uploads")) {
$file = get_file("fields-$idf");
if (!is_string($file)) {
return false; //! report errors
}
return $driver->quoteBinary($file);
}
return $adminer->processInput($field, $value, $function);
}
/** Compute fields() from $_POST edit data
* @return array
*/
@@ -1080,29 +741,6 @@ function fields_from_edit() {
return $return;
}
/** Print results of search in all tables
* @uses $_GET["where"][0]
* @uses $_POST["tables"]
* @return null
*/
function search_tables() {
global $adminer, $connection;
$_GET["where"][0]["val"] = $_POST["query"];
$sep = "<ul>\n";
foreach (table_status('', true) as $table => $table_status) {
$name = $adminer->tableName($table_status);
if (isset($table_status["Engine"]) && $name != "" && (!$_POST["tables"] || in_array($table, $_POST["tables"]))) {
$result = $connection->query("SELECT" . limit("1 FROM " . table($table), " WHERE " . implode(" AND ", $adminer->selectSearchProcess(fields($table), array())), 1));
if (!$result || $result->fetch_row()) {
$print = "<a href='" . h(ME . "select=" . urlencode($table) . "&where[0][op]=" . urlencode($_GET["where"][0]["op"]) . "&where[0][val]=" . urlencode($_GET["where"][0]["val"])) . "'>$name</a>";
echo "$sep<li>" . ($result ? $print : "<p class='error'>$print: " . error()) . "\n";
$sep = "";
}
}
}
echo ($sep ? "<p class='message'>" . lang('No tables.') : "</ul>") . "\n";
}
/** Send headers for export
* @param string
* @param bool
@@ -1168,15 +806,18 @@ function get_temp_dir() {
* @return resource or null for error
*/
function file_open_lock($filename) {
$fp = @fopen($filename, "r+"); // @ - may not exist
if (!$fp) { // c+ is available since PHP 5.2.6
$fp = @fopen($filename, "w"); // @ - may not be writable
if (!$fp) {
return;
}
chmod($filename, 0660);
if (is_link($filename)) {
return; // https://cwe.mitre.org/data/definitions/61.html
}
$fp = @fopen($filename, "c+"); // @ - may not be writable
if (!$fp) {
return;
}
chmod($filename, 0660);
if (!flock($fp, LOCK_EX)) {
fclose($fp);
return;
}
flock($fp, LOCK_EX);
return $fp;
}
@@ -1188,6 +829,13 @@ function file_write_unlock($fp, $data) {
rewind($fp);
fwrite($fp, $data);
ftruncate($fp, strlen($data));
file_unlock($fp);
}
/** Unlock and close a file
* @param resource
*/
function file_unlock($fp) {
flock($fp, LOCK_UN);
fclose($fp);
}
@@ -1198,16 +846,19 @@ function file_write_unlock($fp, $data) {
*/
function password_file($create) {
$filename = get_temp_dir() . "/adminer.key";
$return = @file_get_contents($filename); // @ - may not exist
if ($return || !$create) {
return $return;
if (!$create && !file_exists($filename)) {
return false;
}
$fp = @fopen($filename, "w"); // @ - can have insufficient rights //! is not atomic
if ($fp) {
chmod($filename, 0660);
$fp = file_open_lock($filename);
if (!$fp) {
return false;
}
$return = stream_get_contents($fp);
if (!$return) {
$return = rand_string();
fwrite($fp, $return);
fclose($fp);
file_write_unlock($fp, $return);
} else {
file_unlock($fp);
}
return $return;
}
@@ -1317,14 +968,7 @@ function slow_query($query) {
$connection2 = null;
if (!$slow_query && support("kill") && is_object($connection2 = connect($adminer->credentials())) && ($db == "" || $connection2->select_db($db))) {
$kill = $connection2->result(connection_id()); // MySQL and MySQLi can use thread_id but it's not in PDO_MySQL
?>
<script<?php echo nonce(); ?>>
var timeout = setTimeout(function () {
ajax('<?php echo js_escape(ME); ?>script=kill', function () {
}, 'kill=<?php echo $kill; ?>&token=<?php echo $token; ?>');
}, <?php echo 1000 * $timeout; ?>);
</script>
<?php
echo script("var timeout = setTimeout(function () { ajax('" . js_escape(ME) . "script=kill', function () {}, 'kill=$kill&token=$token'); }, 1000 * $timeout);");
}
ob_flush();
flush();
@@ -1390,129 +1034,3 @@ function lzw_decompress($binary) {
}
return $return;
}
/** Return events to display help on mouse over
* @param string JS expression
* @param bool JS expression
* @return string
*/
function on_help($command, $side = 0) {
return script("mixin(qsl('select, input'), {onmouseover: function (event) { helpMouseover.call(this, event, $command, $side) }, onmouseout: helpMouseout});", "");
}
/** Print edit data form
* @param string
* @param array
* @param mixed
* @param bool
* @return null
*/
function edit_form($table, $fields, $row, $update) {
global $adminer, $token, $error;
$table_name = $adminer->tableName(table_status1($table, true));
page_header(
($update ? lang('Edit') : lang('Insert')),
$error,
array("select" => array($table, $table_name)),
$table_name
);
$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">
<?php
$first = 0;
$is_first = true;
if (!$fields) {
echo "<p class='error'>" . lang('You have no privileges to update this table.') . "\n";
} else {
echo "<table class='layout'>" . script("qsl('table').onkeydown = editingKeydown;");
foreach ($fields as $name => $field) {
echo "<tr><th>" . $adminer->fieldName($field);
$default = $_GET["set"][bracket_escape($name)];
if ($default === null) {
$default = $field["default"];
if ($field["type"] == "bit" && preg_match("~^b'([01]*)'\$~", $default, $regs)) {
$default = $regs[1];
}
if (JUSH == "sql" && preg_match('~binary~', $field["type"])) {
$default = bin2hex($default); // same as UNHEX
}
}
$value = ($row !== null
? ($row[$name] != "" && JUSH == "sql" && preg_match("~enum|set~", $field["type"]) && is_array($row[$name])
? implode(",", $row[$name])
: (is_bool($row[$name]) ? +$row[$name] : $row[$name])
)
: (!$update && $field["auto_increment"]
? ""
: (isset($_GET["select"]) ? false : $default)
)
);
if (!$_POST["save"] && is_string($value)) {
$value = $adminer->editVal($value, $field);
}
$function = ($_POST["save"]
? (string) $_POST["function"][$name]
: ($update && preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"])
? "now"
: ($value === false ? null : ($value !== null ? '' : 'NULL'))
)
);
if (!$_POST && !$update && $value == $field["default"] && preg_match('~^[\w.]+\(~', $value)) {
$function = "SQL";
}
if (preg_match("~time~", $field["type"]) && preg_match('~^CURRENT_TIMESTAMP~i', $value)) {
$value = "";
$function = "now";
}
if ($field["type"] == "uuid" && $value == "uuid()") {
$value = "";
$function = "uuid";
}
if ($is_first && ($field["auto_increment"] || $function == "now" || $function == "uuid")) {
$first++;
} else {
$is_first = false;
}
input($field, $value, $function);
echo "\n";
}
if (!support("table")) {
echo "<tr>"
. "<th><input name='field_keys[]'>"
. script("qsl('input').oninput = fieldChange;")
. "<td class='function'>" . html_select("field_funs[]", $adminer->editFunctions(array("null" => isset($_GET["select"]))))
. "<td><input name='field_vals[]'>"
. "\n"
;
}
echo "</table>\n";
}
echo "<p>\n";
if ($fields) {
echo "<input type='submit' value='" . lang('Save') . "'>\n";
if (!isset($_GET["select"])) {
echo "<input type='submit' name='insert' value='" . ($update
? lang('Save and continue edit')
: lang('Save and insert next')
) . "' title='Ctrl+Shift+Enter'>\n";
echo ($update ? script("qsl('input').onclick = function () { return !ajaxForm(this.form, '" . lang('Saving') . "…', this); };") : "");
}
}
echo ($update ? "<input type='submit' name='delete' value='" . lang('Delete') . "'>" . confirm() . "\n"
: ($_POST || !$fields ? "" : script("focus(qsa('td', qs('#form'))[2*$first+1].firstChild);"))
);
if (isset($_GET["select"])) {
hidden_fields(array("check" => (array) $_POST["check"], "clone" => $_POST["clone"], "all" => $_POST["all"]));
}
?>
<input type="hidden" name="referer" value="<?php echo h(isset($_POST["referer"]) ? $_POST["referer"] : $_SERVER["HTTP_REFERER"]); ?>">
<input type="hidden" name="save" value="1">
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>
<?php
}

View File

@@ -0,0 +1,520 @@
<?php
namespace Adminer;
/** Return <script> element
* @param string
* @param string
* @return string
*/
function script($source, $trailing = "\n") {
return "<script" . nonce() . ">$source</script>$trailing";
}
/** Return <script src> element
* @param string
* @return string
*/
function script_src($url) {
return "<script src='" . h($url) . "'" . nonce() . "></script>\n";
}
/** Get a nonce="" attribute with CSP nonce
* @return string
*/
function nonce() {
return ' nonce="' . get_nonce() . '"';
}
/** Get a target="_blank" attribute
* @return string
*/
function target_blank() {
return ' target="_blank" rel="noreferrer noopener"';
}
/** Escape for HTML
* @param string
* @return string
*/
function h($string) {
return str_replace("\0", "&#0;", htmlspecialchars($string, ENT_QUOTES, 'utf-8'));
}
/** Convert \n to <br>
* @param string
* @return string
*/
function nl_br($string) {
return str_replace("\n", "<br>", $string); // nl2br() uses XHTML before PHP 5.3
}
/** Generate HTML checkbox
* @param string
* @param string
* @param bool
* @param string
* @param string
* @param string
* @param string
* @return string
*/
function checkbox($name, $value, $checked, $label = "", $onclick = "", $class = "", $labelled_by = "") {
$return = "<input type='checkbox' name='$name' value='" . h($value) . "'"
. ($checked ? " checked" : "")
. ($labelled_by ? " aria-labelledby='$labelled_by'" : "")
. ">"
. ($onclick ? script("qsl('input').onclick = function () { $onclick };", "") : "")
;
return ($label != "" || $class ? "<label" . ($class ? " class='$class'" : "") . ">$return" . h($label) . "</label>" : $return);
}
/** Generate list of HTML options
* @param array array of strings or arrays (creates optgroup)
* @param mixed
* @param bool always use array keys for value="", otherwise only string keys are used
* @return string
*/
function optionlist($options, $selected = null, $use_keys = false) {
$return = "";
foreach ($options as $k => $v) {
$opts = array($k => $v);
if (is_array($v)) {
$return .= '<optgroup label="' . h($k) . '">';
$opts = $v;
}
foreach ($opts as $key => $val) {
$return .= '<option'
. ($use_keys || is_string($key) ? ' value="' . h($key) . '"' : '')
. ($selected !== null && ($use_keys || is_string($key) ? (string) $key : $val) === $selected ? ' selected' : '')
. '>' . h($val)
;
}
if (is_array($v)) {
$return .= '</optgroup>';
}
}
return $return;
}
/** Generate HTML <select>
* @param string
* @param array
* @param string
* @param string
* @param string
* @return string
*/
function html_select($name, $options, $value = "", $onchange = "", $labelled_by = "") {
return "<select name='" . h($name) . "'"
. ($labelled_by ? " aria-labelledby='$labelled_by'" : "")
. ">" . optionlist($options, $value) . "</select>"
. ($onchange ? script("qsl('select').onchange = function () { $onchange };", "") : "")
;
}
/** Generate HTML radio list
* @param string
* @param array
* @param string
* @return string
*/
function html_radios($name, $options, $value = "") {
$return = "";
foreach ($options as $key => $val) {
$return .= "<label><input type='radio' name='" . h($name) . "' value='" . h($key) . "'" . ($key == $value ? " checked" : "") . ">" . h($val) . "</label>";
}
return $return;
}
/** Get onclick confirmation
* @param string
* @param string
* @return string
*/
function confirm($message = "", $selector = "qsl('input')") {
return script("$selector.onclick = function () { return confirm('" . ($message ? js_escape($message) : lang('Are you sure?')) . "'); };", "");
}
/** Print header for hidden fieldset (close by </div></fieldset>)
* @param string
* @param string
* @param bool
* @return null
*/
function print_fieldset($id, $legend, $visible = false) {
echo "<fieldset><legend>";
echo "<a href='#fieldset-$id'>$legend</a>";
echo script("qsl('a').onclick = partial(toggle, 'fieldset-$id');", "");
echo "</legend>";
echo "<div id='fieldset-$id'" . ($visible ? "" : " class='hidden'") . ">\n";
}
/** Return class='active' if $bold is true
* @param bool
* @param string
* @return string
*/
function bold($bold, $class = "") {
return ($bold ? " class='active $class'" : ($class ? " class='$class'" : ""));
}
/** Escape string for JavaScript apostrophes
* @param string
* @return string
*/
function js_escape($string) {
return addcslashes($string, "\r\n'\\/"); // slash for <script>
}
/** Generate page number for pagination
* @param int
* @param int
* @return string
*/
function pagination($page, $current) {
return " " . ($page == $current
? $page + 1
: '<a href="' . h(remove_from_uri("page") . ($page ? "&page=$page" . ($_GET["next"] ? "&next=" . urlencode($_GET["next"]) : "") : "")) . '">' . ($page + 1) . "</a>"
);
}
/** Print hidden fields
* @param array
* @param array
* @param string
* @return bool
*/
function hidden_fields($process, $ignore = array(), $prefix = '') {
$return = false;
foreach ($process as $key => $val) {
if (!in_array($key, $ignore)) {
if (is_array($val)) {
hidden_fields($val, array(), $key);
} else {
$return = true;
echo '<input type="hidden" name="' . h($prefix ? $prefix . "[$key]" : $key) . '" value="' . h($val) . '">';
}
}
}
return $return;
}
/** Print hidden fields for GET forms
* @return null
*/
function hidden_fields_get() {
echo (sid() ? '<input type="hidden" name="' . session_name() . '" value="' . h(session_id()) . '">' : '');
echo (SERVER !== null ? '<input type="hidden" name="' . DRIVER . '" value="' . h(SERVER) . '">' : "");
echo '<input type="hidden" name="username" value="' . h($_GET["username"]) . '">';
}
/** Print enum input field
* @param string "radio"|"checkbox"
* @param string
* @param array
* @param mixed string|array
* @param string
* @return null
*/
function enum_input($type, $attrs, $field, $value, $empty = null) {
global $adminer;
preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
$return = ($empty !== null ? "<label><input type='$type'$attrs value='$empty'" . ((is_array($value) ? in_array($empty, $value) : $value === $empty) ? " checked" : "") . "><i>" . lang('empty') . "</i></label>" : "");
foreach ($matches[1] as $i => $val) {
$val = stripcslashes(str_replace("''", "'", $val));
$checked = (is_array($value) ? in_array($val, $value) : $value === $val);
$return .= " <label><input type='$type'$attrs value='" . h($val) . "'" . ($checked ? ' checked' : '') . '>' . h($adminer->editVal($val, $field)) . '</label>';
}
return $return;
}
/** Print edit input field
* @param array one field from fields()
* @param mixed
* @param string
* @param bool
* @return null
*/
function input($field, $value, $function, $autofocus = false) {
global $driver, $adminer;
$name = h(bracket_escape($field["field"]));
echo "<td class='function'>";
if (is_array($value) && !$function) {
$value = json_encode($value, 128); // 128 - JSON_PRETTY_PRINT available since PHP 5.4
$function = "json";
}
$reset = (JUSH == "mssql" && $field["auto_increment"]);
if ($reset && !$_POST["save"]) {
$function = null;
}
$functions = (isset($_GET["select"]) || $reset ? array("orig" => lang('original')) : array()) + $adminer->editFunctions($field);
$disabled = stripos($field["default"], "GENERATED ALWAYS AS ") === 0 ? " disabled=''" : "";
$attrs = " name='fields[$name]'$disabled" . ($autofocus ? " autofocus" : "");
$enums = $driver->enumLength($field);
if ($enums) {
$field["type"] = "enum";
$field["length"] = $enums;
}
echo $driver->unconvertFunction($field) . " ";
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]'$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))
) . '<td>';
$input = $adminer->editInput($_GET["edit"], $field, $attrs, $value); // usage in call is without a table
if ($input != "") {
echo $input;
} elseif (preg_match('~bool~', $field["type"])) {
echo "<input type='hidden'$attrs value='0'>"
. "<input type='checkbox'" . (preg_match('~^(1|t|true|y|yes|on)$~i', $value) ? " checked='checked'" : "") . "$attrs value='1'>";
} elseif ($field["type"] == "set") {
preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
foreach ($matches[1] as $i => $val) {
$val = stripcslashes(str_replace("''", "'", $val));
$checked = in_array($val, explode(",", $value), true);
echo " <label><input type='checkbox' name='fields[$name][$i]' value='" . h($val) . "'" . ($checked ? ' checked' : '') . ">" . h($adminer->editVal($val, $field)) . '</label>';
}
} elseif (preg_match('~blob|bytea|raw|file~', $field["type"]) && ini_bool("file_uploads")) {
echo "<input type='file' name='fields-$name'>";
} elseif (($text = preg_match('~text|lob|memo~i', $field["type"])) || preg_match("~\n~", $value)) {
if ($text && JUSH != "sqlite") {
$attrs .= " cols='50' rows='12'";
} else {
$rows = min(12, substr_count($value, "\n") + 1);
$attrs .= " cols='30' rows='$rows'" . ($rows == 1 ? " style='height: 1.2em;'" : ""); // 1.2em - line-height
}
echo "<textarea$attrs>" . h($value) . '</textarea>';
} elseif ($function == "json" || preg_match('~^jsonb?$~', $field["type"])) {
echo "<textarea$attrs cols='50' rows='12' class='jush-js'>" . h($value) . '</textarea>';
} else {
// int(3) is only a display hint
$types = $driver->types();
$maxlength = (!preg_match('~int~', $field["type"]) && preg_match('~^(\d+)(,(\d+))?$~', $field["length"], $match)
? ((preg_match("~binary~", $field["type"]) ? 2 : 1) * $match[1] + ($match[3] ? 1 : 0) + ($match[2] && !$field["unsigned"] ? 1 : 0))
: ($types[$field["type"]] ? $types[$field["type"]] + ($field["unsigned"] ? 0 : 1) : 0)
);
if (JUSH == 'sql' && min_version(5.6) && preg_match('~time~', $field["type"])) {
$maxlength += 7; // microtime
}
// type='date' and type='time' display localized value which may be confusing, type='datetime' uses 'T' as date and time separator
echo "<input"
. ((!$has_function || $function === "") && preg_match('~(?<!o)int(?!er)~', $field["type"]) && !preg_match('~\[\]~', $field["full_type"]) ? " type='number'" : "")
. " value='" . h($value) . "'" . ($maxlength ? " data-maxlength='$maxlength'" : "")
. (preg_match('~char|binary~', $field["type"]) && $maxlength > 20 ? " size='40'" : "")
. "$attrs>"
;
}
echo $adminer->editHint($_GET["edit"], $field, $value);
// skip 'original'
$first = 0;
foreach ($functions as $key => $val) {
if ($key === "" || !$val) {
break;
}
$first++;
}
if ($first) {
echo script("mixin(qsl('td'), {onchange: partial(skipOriginal, $first), oninput: function () { this.onchange(); }});");
}
}
}
/** Process edit input field
* @param one field from fields()
* @return string or false to leave the original value
*/
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];
if ($field["type"] == "enum" || $driver->enumLength($field)) {
if ($value == -1) {
return false;
}
if ($value == "") {
return "NULL";
}
}
if ($field["auto_increment"] && $value == "") {
return null;
}
if ($function == "orig") {
return (preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"]) ? idf_escape($field["field"]) : false);
}
if ($function == "NULL") {
return "NULL";
}
if ($field["type"] == "set") {
$value = implode(",", (array) $value);
}
if ($function == "json") {
$function = "";
$value = json_decode($value, true);
if (!is_array($value)) {
return false; //! report errors
}
return $value;
}
if (preg_match('~blob|bytea|raw|file~', $field["type"]) && ini_bool("file_uploads")) {
$file = get_file("fields-$idf");
if (!is_string($file)) {
return false; //! report errors
}
return $driver->quoteBinary($file);
}
return $adminer->processInput($field, $value, $function);
}
/** Print results of search in all tables
* @uses $_GET["where"][0]
* @uses $_POST["tables"]
* @return null
*/
function search_tables() {
global $adminer, $connection;
$_GET["where"][0]["val"] = $_POST["query"];
$sep = "<ul>\n";
foreach (table_status('', true) as $table => $table_status) {
$name = $adminer->tableName($table_status);
if (isset($table_status["Engine"]) && $name != "" && (!$_POST["tables"] || in_array($table, $_POST["tables"]))) {
$result = $connection->query("SELECT" . limit("1 FROM " . table($table), " WHERE " . implode(" AND ", $adminer->selectSearchProcess(fields($table), array())), 1));
if (!$result || $result->fetch_row()) {
$print = "<a href='" . h(ME . "select=" . urlencode($table) . "&where[0][op]=" . urlencode($_GET["where"][0]["op"]) . "&where[0][val]=" . urlencode($_GET["where"][0]["val"])) . "'>$name</a>";
echo "$sep<li>" . ($result ? $print : "<p class='error'>$print: " . error()) . "\n";
$sep = "";
}
}
}
echo ($sep ? "<p class='message'>" . lang('No tables.') : "</ul>") . "\n";
}
/** Return events to display help on mouse over
* @param string JS expression
* @param bool JS expression
* @return string
*/
function on_help($command, $side = 0) {
return script("mixin(qsl('select, input'), {onmouseover: function (event) { helpMouseover.call(this, event, $command, $side) }, onmouseout: helpMouseout});", "");
}
/** Print edit data form
* @param string
* @param array
* @param mixed
* @param bool
* @return null
*/
function edit_form($table, $fields, $row, $update) {
global $adminer, $token, $error;
$table_name = $adminer->tableName(table_status1($table, true));
page_header(
($update ? lang('Edit') : lang('Insert')),
$error,
array("select" => array($table, $table_name)),
$table_name
);
$adminer->editRowPrint($table, $fields, $row, $update);
if ($row === false) {
echo "<p class='error'>" . lang('No rows.') . "\n";
return;
}
echo "<form action='' method='post' enctype='multipart/form-data' id='form'>\n";
if (!$fields) {
echo "<p class='error'>" . lang('You have no privileges to update this table.') . "\n";
} else {
echo "<table class='layout'>" . script("qsl('table').onkeydown = editingKeydown;");
$autofocus = !$_POST;
foreach ($fields as $name => $field) {
echo "<tr><th>" . $adminer->fieldName($field);
$default = $_GET["set"][bracket_escape($name)];
if ($default === null) {
$default = $field["default"];
if ($field["type"] == "bit" && preg_match("~^b'([01]*)'\$~", $default, $regs)) {
$default = $regs[1];
}
if (JUSH == "sql" && preg_match('~binary~', $field["type"])) {
$default = bin2hex($default); // same as UNHEX
}
}
$value = ($row !== null
? ($row[$name] != "" && JUSH == "sql" && preg_match("~enum|set~", $field["type"]) && is_array($row[$name])
? implode(",", $row[$name])
: (is_bool($row[$name]) ? +$row[$name] : $row[$name])
)
: (!$update && $field["auto_increment"]
? ""
: (isset($_GET["select"]) ? false : $default)
)
);
if (!$_POST["save"] && is_string($value)) {
$value = $adminer->editVal($value, $field);
}
$function = ($_POST["save"]
? (string) $_POST["function"][$name]
: ($update && preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"])
? "now"
: ($value === false ? null : ($value !== null ? '' : 'NULL'))
)
);
if (!$_POST && !$update && $value == $field["default"] && preg_match('~^[\w.]+\(~', $value)) {
$function = "SQL";
}
if (preg_match("~time~", $field["type"]) && preg_match('~^CURRENT_TIMESTAMP~i', $value)) {
$value = "";
$function = "now";
}
if ($field["type"] == "uuid" && $value == "uuid()") {
$value = "";
$function = "uuid";
}
if ($autofocus !== false) {
$autofocus = ($field["auto_increment"] || $function == "now" || $function == "uuid" ? null : true); // null - don't autofocus this input but check the next one
}
input($field, $value, $function, $autofocus);
if ($autofocus) {
$autofocus = false;
}
echo "\n";
}
if (!support("table")) {
echo "<tr>"
. "<th><input name='field_keys[]'>"
. script("qsl('input').oninput = fieldChange;")
. "<td class='function'>" . html_select("field_funs[]", $adminer->editFunctions(array("null" => isset($_GET["select"]))))
. "<td><input name='field_vals[]'>"
. "\n"
;
}
echo "</table>\n";
}
echo "<p>\n";
if ($fields) {
echo "<input type='submit' value='" . lang('Save') . "'>\n";
if (!isset($_GET["select"])) {
echo "<input type='submit' name='insert' value='" . ($update
? lang('Save and continue edit')
: lang('Save and insert next')
) . "' title='Ctrl+Shift+Enter'>\n";
echo ($update ? script("qsl('input').onclick = function () { return !ajaxForm(this.form, '" . lang('Saving') . "…', this); };") : "");
}
}
echo ($update ? "<input type='submit' name='delete' value='" . lang('Delete') . "'>" . confirm() . "\n" : "");
if (isset($_GET["select"])) {
hidden_fields(array("check" => (array) $_POST["check"], "clone" => $_POST["clone"], "all" => $_POST["all"]));
}
?>
<input type="hidden" name="referer" value="<?php echo h(isset($_POST["referer"]) ? $_POST["referer"] : $_SERVER["HTTP_REFERER"]); ?>">
<input type="hidden" name="save" value="1">
<input type="hidden" name="token" value="<?php echo $token; ?>">
</form>
<?php
}

View File

@@ -63,10 +63,12 @@ function get_lang() {
* @param int
* @return string
*/
// this is matched by compile.php
function lang($idf, $number = null) {
global $LANG, $translations;
$translation = ($translations[$idf] ?: $idf);
if (is_array($translation)) {
// this is matched by compile.php
$pos = ($number == 1 ? 0
: ($LANG == 'cs' || $LANG == 'sk' ? ($number && $number < 5 ? 1 : 2) // different forms for 1, 2-4, other
: ($LANG == 'fr' ? (!$number ? 0 : 1) // different forms for 0-1, other
@@ -75,8 +77,8 @@ function lang($idf, $number = null) {
: ($LANG == 'lt' ? ($number % 10 == 1 && $number % 100 != 11 ? 0 : ($number % 10 > 1 && $number / 10 % 10 != 1 ? 1 : 2)) // different forms for 1, 12-19, other
: ($LANG == 'lv' ? ($number % 10 == 1 && $number % 100 != 11 ? 0 : ($number ? 1 : 2)) // different forms for 1 except 11, other, 0
: (in_array($LANG, array('bs', 'ru', 'sr', 'uk')) ? ($number % 10 == 1 && $number % 100 != 11 ? 0 : ($number % 10 > 1 && $number % 10 < 5 && $number / 10 % 10 != 1 ? 1 : 2)) // different forms for 1 except 11, 2-4 except 12-14, other
: 1 // different forms for 1, other
)))))))); // http://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
: 1)))))))) // different forms for 1, other
; // http://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
$translation = $translation[$pos];
}
$args = func_get_args();

View File

@@ -1,4 +1,4 @@
<?php
namespace Adminer;
$VERSION = "5.0.5";
$VERSION = "5.0.6";

View File

@@ -6,6 +6,7 @@
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
// this is matched by compile.php
namespace Adminer;
@@ -15,6 +16,7 @@ include "./include/tmpfile.inc.php";
if (isset($_GET["select"]) && ($_POST["edit"] || $_POST["clone"]) && !$_POST["save"]) {
$_GET["edit"] = $_GET["select"];
}
// this is matched by compile.php
if (isset($_GET["callf"])) {
$_GET["call"] = $_GET["callf"];
}

View File

@@ -19,7 +19,7 @@ if (JUSH == "mongo") { // doesn't support primary key
}
$row = $_POST;
if ($row) {
set_adminer_settings(array("index_options" => $row["options"]));
save_settings(array("index_options" => $row["options"]));
}
if ($_POST && !$error && !$_POST["add"] && !$_POST["drop_col"]) {
$alter = array();
@@ -97,7 +97,7 @@ if (!$row) {
$row["indexes"] = $indexes;
}
$lengths = (JUSH == "sql" || JUSH == "mssql");
$show_options = ($_POST ? $_POST["options"] : adminer_setting("index_options"));
$show_options = ($_POST ? $_POST["options"] : get_setting("index_options"));
?>
<form action="" method="post">

View File

@@ -7,7 +7,7 @@ $indexes = indexes($TABLE);
$fields = fields($TABLE);
$foreign_keys = column_foreign_keys($TABLE);
$oid = $table_status["Oid"];
parse_str($_COOKIE["adminer_import"], $adminer_import);
$adminer_import = get_settings("adminer_import");
$rights = array(); // privilege => 0
$columns = array(); // selectable columns
@@ -83,7 +83,7 @@ if ($_POST && !$error) {
}
$where_check = ($where_check ? "\nWHERE " . implode(" AND ", $where_check) : "");
if ($_POST["export"]) {
cookie("adminer_import", "output=" . urlencode($_POST["output"]) . "&format=" . urlencode($_POST["format"]));
save_settings(array("output" => $_POST["output"], "format" => $_POST["format"]), "adminer_import");
dump_headers($TABLE);
$adminer->dumpTable($TABLE, "");
$from = ($select ? implode(", ", $select) : "*")
@@ -195,7 +195,7 @@ if ($_POST && !$error) {
} elseif (!preg_match('~~u', $file)) {
$error = lang('File must be in UTF-8 encoding.');
} else {
cookie("adminer_import", "output=" . urlencode($adminer_import["output"]) . "&format=" . urlencode($_POST["separator"]));
save_settings(array("output" => $adminer_import["output"], "format" => $_POST["separator"]), "adminer_import");
$result = true;
$cols = array_keys($fields);
preg_match_all('~(?>"[^"]*"|[^"\r\n]+)+~', $file, $matches);
@@ -453,7 +453,7 @@ if (!$columns && support("table")) {
$value = $_POST["val"][$unique_idf][bracket_escape($key)];
$editable = !is_array($row[$key]) && is_utf8($val) && $rows[$n][$key] == $row[$key] && !$functions[$key] && !$field["generated"];
$text = preg_match('~text|json|lob~', $field["type"]);
echo "<td id='$id'";
echo "<td id='$id'" . (preg_match(number_type(), $field["type"]) && is_numeric(strip_tags($val)) ? " class='number'" : "");
if (($_GET["modify"] && $editable) || $value !== null) {
$h_value = h($value !== null ? $value : $row[$key]);
echo ">" . ($text ? "<textarea name='$id' cols='30' rows='" . (substr_count($row[$key], "\n") + 1) . "'>$h_value</textarea>" : "<input name='$id' value='$h_value' size='$lengths[$key]'>");

View File

@@ -2,6 +2,7 @@
namespace Adminer;
if (!$error && $_POST["export"]) {
save_settings(array("output" => $_POST["output"], "format" => $_POST["format"]), "adminer_import");
dump_headers("sql");
$adminer->dumpTable("", "");
$adminer->dumpData("", "table", $_POST["query"]);
@@ -64,7 +65,7 @@ if (!$error && $_POST) {
$errors = array();
$parse = '[\'"' . (JUSH == "sql" ? '`#' : (JUSH == "sqlite" ? '`[' : (JUSH == "mssql" ? '[' : ''))) . ']|/\*|-- |$' . (JUSH == "pgsql" ? '|\$[^$]*\$' : '');
$total_start = microtime(true);
parse_str($_COOKIE["adminer_export"], $adminer_export);
$adminer_export = get_settings("adminer_import"); // this doesn't offer SQL export so we match the import/export style at select
$dump_format = $adminer->dumpFormat();
unset($dump_format["sql"]);
@@ -89,8 +90,8 @@ if (!$error && $_POST) {
$pattern = ($found == '/*' ? '\*/'
: ($found == '[' ? ']'
: (preg_match('~^-- |^#~', $found) ? "\n"
: preg_quote($found) . ($c_style_escapes ? "|\\\\." : "")
)));
: preg_quote($found) . ($c_style_escapes ? "|\\\\." : "")))
);
while (preg_match("($pattern|\$)s", $query, $match, PREG_OFFSET_CAPTURE, $offset)) {
$s = $match[0][0];

View File

@@ -12,9 +12,8 @@ thead td, thead th { color: #a8b05f; background: #011d35; }
thead th a { color: #a8b05f; }
fieldset { border-color: #16548a; }
code { background: #11385a; }
code[class^="jush-"] { color: #002240; background: #81a0bc; padding: .2em .5em; }
tbody tr:hover td, tbody tr:hover th { background: #133553; }
pre.jush { background: #a7c3dc; }
pre.jush { background: #11385a; }
input.default { box-shadow: 1px 1px 1px #888; }
input.required, input.maxlength { box-shadow: 1px 1px 1px red; }
.version { color: #888; }

View File

@@ -665,7 +665,7 @@ function indexesAddColumn(prefix) {
* @param string
*/
function sqlSubmit(form, root) {
if (encodeURIComponent(form['query'].value).length < 2e3) {
if (encodeURIComponent(form['query'].value).length < 500) {
form.action = root
+ '&sql=' + encodeURIComponent(form['query'].value)
+ (form['limit'].value ? '&limit=' + +form['limit'].value : '')

View File

@@ -880,16 +880,6 @@ function addEvent(el, action, handler) {
}
}
/** Defer focusing element
* @param HTMLElement
*/
function focus(el) {
setTimeout(function () {
// this has to be an anonymous function because Firefox passes some arguments to setTimeout callback
el.focus();
}, 0);
}
/** Clone node and setup submit highlighting
* @param HTMLElement
* @return HTMLElement

View File

@@ -1,9 +1,22 @@
Adminer 5.0.6 (released 2025-03-17):
Align numbers right (bug #912)
Display comment in title of field
Remember export setting at SQL command
Shorten queries saved from SQL command to URL (bug #917)
SQL textarea: Open help on Ctrl+click
Security: Disallow writing temporary files to symlinks (bug SF-855)
MariaDB: Display MariaDB instead of MySQL
CSS: Dark mode syntax highlighting
CSS: Dark input fields in dark mode
Designs named adminer-dark.css use dark basic style
Plugins: Add method syntaxHighlighting()
Adminer 5.0.5 (released 2025-03-13):
MySQL: Display converting function for binary, bit or geometry fields
MySQL: Display default values of binary columns
MySQL: Allow setting default values of json column
MariaDB: Don't display NULL as default value (regression from 5.0.0)
PostgreSQL PDO: Escape bytea values (bug #218)
PostgreSQL PDO: Escape bytea values (bug SF-218)
CockroachDB: Display version
CockroachDB: Recognize unique_rowid() as auto_increment
MS SQL: Fix editing rows with datetime column in primary key
@@ -18,7 +31,7 @@ Fix gzip export (bug #896, regression from 5.0.0)
Fix importing multiple SQL files not terminated by semicolon
Use <datalist> for altering collations
MySQL: Allow setting default values of text column
MySQL: Stop treating enum and set as numbers (bug #475)
MySQL: Stop treating enum and set as numbers (bug SF-475)
MySQL, MariaDB: Fix default values with ' (bug #895)
MariaDB: Fix creating and altering generated columns (bug #897)
PostgreSQL: Fix "where" and "order" privileges (bug #902, regression from 5.0.2)
@@ -28,30 +41,30 @@ Elastic: Fix displaying sparse rows (PR #893)
Plugins: Add method dumpFooter()
Adminer 5.0.2 (released 2025-03-10):
PostgreSQL: Fix setting NULL and original value on enum (bug #884)
PostgreSQL: Fix setting NULL and original value on enum (bug SF-884)
CockroachDB: Add support via PostgreSQL driver
Elasticsearch: Add support for "where" and "order" field privilege
Adminer 5.0.1 (released 2025-03-07):
Fix bulk operations with tables (regression from 5.0.0)
Remove duplicate columns from select (bug #670)
MariaDB: Fix link to status variable doc (bug #658)
Remove duplicate columns from select (bug SF-670)
MariaDB: Fix link to status variable doc (bug SF-658)
PostgreSQL: Support indexes on materialized views (PR #467)
Elasticsearch: Drop support for version < 7
Adminer 5.0.0 (released 2025-03-07):
Speed up with disabled output buffering
Allow creating generated columns (bug #857)
Allow creating generated columns (bug SF-857)
Don't autofocus computed fields in insert form
Skip generated columns in multi-edit (bug #882)
Skip generated columns in multi-edit (bug SF-882)
MySQL: Display generated value in table structure
MySQL: Drop support for MySQL 4
PostgreSQL: Compute size of all databases (bug #881)
PostgreSQL: Compute size of all databases (bug SF-881)
PostgreSQL: Do not alter indexes with expressions
PostgreSQL: Fix export of indexes with expressions (bug #768)
PostgreSQL: Fix export of indexes with expressions (bug SF-768)
PostgreSQL: Display ENUM types
PostgreSQL: Export ENUM types (bug #587)
PostgreSQL: Display ? instead of -1 rows in table overview (bug #883)
PostgreSQL: Export ENUM types (bug SF-587)
PostgreSQL: Display ? instead of -1 rows in table overview (bug SF-883)
PostgreSQL: Show accessible databases to non-owners (regression from 4.9.1)
PostgreSQL: Skip editing generated columns
PostgreSQL, MS SQL, Oracle: Hide table actions for information_schema
@@ -60,10 +73,10 @@ SQLite: Support generated columns
SQLite: Add command Check tables
SQLite: Display all rows of variable values
SQLite: Remove support for SQLite version 2
MS SQL: Support export (bug #480)
MS SQL: Support export (bug SF-480)
MS SQL: Display foreign keys ON UPDATE and ON DELETE
MS SQL: Support computed columns
MS SQL: Fix CSV import (bug #859)
MS SQL: Fix CSV import (bug SF-859)
MS SQL: Fix altering foreign key
MS SQL PDO: Support offset
MS SQL: Remove support for MSSQL extension
@@ -82,28 +95,28 @@ Hide index column options by default
Offer original values in multi-row editing (regression from 4.16.0)
Print SQL errors as comments in export (regression from 3.2.0)
MySQL, PostgreSQL, MS SQL: Support CHECK constraint
MySQL: Show comments at routine call (bug #874)
MySQL: Show comments at routine call (bug SF-874)
MySQL: Don't offer empty enum value in edit
MySQL 9+: Support vector type
PostgreSQL: Link user defined types
PostgreSQL: Constraint enum values in editing (bug #270)
PostgreSQL: Constraint enum values in editing (bug SF-270)
PostgreSQL: Export functions
PostgreSQL 8+: Fix exporting table constraints
SQLite: Show all supported pragmas in Variables
MS SQL: Allow altering table in non-default schema (bug #405)
MS SQL: Fix default values (bug #732, bug #733)
MS SQL: Allow altering table in non-default schema (bug SF-405)
MS SQL: Fix default values (bug SF-732, bug SF-733)
MS SQL: Fix length of nvarchar columns
Editor PDO: Select value of foreign key in edit (bug #847)
Editor PDO: Select value of foreign key in edit (bug SF-847)
Mobile devices: Use device width
Adminer 4.16.0 (released 2025-02-20):
MySQL: Fix saving bit(64) values (bug #839)
PostgreSQL: Preserve whitespace in EXPLAIN (bug #827)
MySQL: Fix saving bit(64) values (bug SF-839)
PostgreSQL: Preserve whitespace in EXPLAIN (bug SF-827)
PostgreSQL: Support SSL
PostgreSQL: Support altering auto_increment (bug #761)
SQLite: Fix altering forign keys (bug #841)
SQLite: Fix expressions in default values (bug #860)
MS SQL: Foreign keys in non-default schema (bug #833)
PostgreSQL: Support altering auto_increment (bug SF-761)
SQLite: Fix altering forign keys (bug SF-841)
SQLite: Fix expressions in default values (bug SF-860)
MS SQL: Foreign keys in non-default schema (bug SF-833)
Oracle: Include tables granted by other user
MongoDB: Execute commands against the selected DB
@@ -170,28 +183,28 @@ PostgreSQL: Don't reset table comments (regression from 4.2.0)
PostgreSQL PDO: Allow editing rows identified by boolean column (PR #380)
Adminer 4.8.1 (released 2021-05-14):
Internet Explorer or PDO in Adminer 4.7.8-4.8.0: Fix XSS in doc_link (bug #797)
Fix more PHP 8 warnings (bug #781)
Avoid PHP warnings with PDO drivers (bug #786, regression from 4.7.8)
MySQL: Allow moving views to other DB and renaming DB with views (bug #783)
Internet Explorer or PDO in Adminer 4.7.8-4.8.0: Fix XSS in doc_link (bug SF-797)
Fix more PHP 8 warnings (bug SF-781)
Avoid PHP warnings with PDO drivers (bug SF-786, regression from 4.7.8)
MySQL: Allow moving views to other DB and renaming DB with views (bug SF-783)
MariaDB: Do not treat sequences as views (PR #416)
PostgreSQL: Support UPDATE OF triggers (bug #789)
PostgreSQL: Support UPDATE OF triggers (bug SF-789)
PostgreSQL: Support triggers with more events (OR)
PostgreSQL: Fix parsing of foreign keys with non-ASCII column names
PostgreSQL < 10 PDO: Avoid displaying GENERATED ALWAYS BY IDENTITY everywhere (bug #785, regression from 4.7.9)
SQLite: Fix displayed types (bug #784, regression from 4.8.0)
PostgreSQL < 10 PDO: Avoid displaying GENERATED ALWAYS BY IDENTITY everywhere (bug SF-785, regression from 4.7.9)
SQLite: Fix displayed types (bug SF-784, regression from 4.8.0)
Adminer 4.8.0 (released 2021-02-10):
Support function default values in insert (bug #713)
Support function default values in insert (bug SF-713)
Allow SQL pseudo-function in insert
Skip date columns for non-date values in search anywhere
Add DB version to comment in export
Support PHP 8 in create table (regression from 4.7.9)
MySQL 8: Fix EXPLAIN in SQL command
PostgreSQL: Create PRIMARY KEY for auto increment columns
PostgreSQL: Avoid exporting empty sequence last value (bug #768)
PostgreSQL: Avoid exporting empty sequence last value (bug SF-768)
PostgreSQL: Do not show triggers from other schemas (PR #412)
PostgreSQL: Fix multi-parameter functions in default values (bug #736)
PostgreSQL: Fix multi-parameter functions in default values (bug SF-736)
PostgreSQL: Fix displaying NULL bytea fields
PostgreSQL PDO: Do not select NULL function for false values in edit
Oracle: Alter indexes
@@ -202,21 +215,21 @@ MongoDB: Handle errors
SimpleDB, Firebird, ClickHouse: Move to plugin
Adminer 4.7.9 (released 2021-02-07):
Fix XSS in browsers which don't encode URL parameters (bug #775, regression from 4.7.0)
Fix XSS in browsers which don't encode URL parameters (bug SF-775, regression from 4.7.0)
Elasticsearch, ClickHouse: Do not print response if HTTP code is not 200
Don't syntax highlight during IME composition (bug #747)
Quote values with leading and trailing zeroes in CSV export (bug #777)
Don't syntax highlight during IME composition (bug SF-747)
Quote values with leading and trailing zeroes in CSV export (bug SF-777)
Link URLs in SQL command (PR #411)
Fix displayed foreign key columns from other DB (bug #766)
Fix displayed foreign key columns from other DB (bug SF-766)
Re-enable PHP warnings (regression from 4.7.8)
MySQL: Do not export names in quotes with sql_mode='ANSI_QUOTES' (bug #749)
MySQL: Do not export names in quotes with sql_mode='ANSI_QUOTES' (bug SF-749)
MySQL: Avoid error in PHP 8 when connecting to socket (PR #409)
MySQL: Don't quote default value of text fields (bug #779)
MySQL: Don't quote default value of text fields (bug SF-779)
PostgreSQL: Export all FKs after all CREATE TABLE (PR #351)
PostgreSQL: Fix dollar-quoted syntax highlighting (bug #738)
PostgreSQL: Fix dollar-quoted syntax highlighting (bug SF-738)
PostgreSQL: Do not show view definition from other schema (PR #392)
PostgreSQL: Use bigserial for bigint auto increment (bug #765, regression from 3.0.0)
PostgreSQL PDO: Support PgBouncer, unsupport PostgreSQL < 9.1 (bug #771)
PostgreSQL: Use bigserial for bigint auto increment (bug SF-765, regression from 3.0.0)
PostgreSQL PDO: Support PgBouncer, unsupport PostgreSQL < 9.1 (bug SF-771)
PostgreSQL 10: Support GENERATED ALWAYS BY IDENTITY (PR #386)
PostgreSQL 10: Support partitioned tables (PR #396)
PostgreSQL 11: Create PRIMARY KEY for auto increment columns
@@ -224,12 +237,12 @@ SQLite: Set busy_timeout to 500
MS SQL: Don't truncate comments to 30 chars (PR #376)
Elasticsearch 6: Fix displaying type mapping (PR #402)
MongoDB: Fix password-less check in the mongo extension (PR #405)
Editor: Cast to string when searching (bug #325)
Editor: Cast to string when searching (bug SF-325)
Editor: Avoid trailing dot in export filename
Adminer 4.7.8 (released 2020-12-06):
Support PHP 8
Disallow connecting to privileged ports (bug #769)
Disallow connecting to privileged ports (bug SF-769)
Adminer 4.7.7 (released 2020-05-11):
Fix open redirect if Adminer is accessible at //adminer.php%2F@
@@ -238,15 +251,15 @@ Adminer 4.7.6 (released 2020-01-31):
Speed up alter table form (regression from 4.4.0)
Fix clicking on non-input fields in alter table (regression from 4.6.2)
Display time of procedure execution
Disallow connecting to ports > 65535 (bug #730)
Disallow connecting to ports > 65535 (bug SF-730)
MySQL: Always set foreign_key_checks in export
PostgreSQL: Support exporting views
Editor: Fix focusing foreign key search in select
Adminer 4.7.5 (released 2019-11-13):
Add id="" to cells with failed inline edit (bug #708)
PostgreSQL: Fix getting default value in PostgreSQL 12 (bug #719)
PostgreSQL, Oracle: Set schema for EXPLAIN queries in SQL command (bug #706)
Add id="" to cells with failed inline edit (bug SF-708)
PostgreSQL: Fix getting default value in PostgreSQL 12 (bug SF-719)
PostgreSQL, Oracle: Set schema for EXPLAIN queries in SQL command (bug SF-706)
ClickHouse: SQL command
Swedish translation
@@ -254,40 +267,40 @@ Adminer 4.7.4 (released 2019-10-22):
Fix XSS if Adminer is accessible at URL /data:
Adminer 4.7.3 (released 2019-08-27):
Allow editing foreign keys pointing to tables in other database/schema (bug #694)
Fix blocking of concurrent instances in PHP >7.2 (bug #703)
MySQL: Speed up displaying tables in large databases (bug #700, regression from 4.7.2)
MySQL: Allow editing rows identified by negative floats (bug #695)
Allow editing foreign keys pointing to tables in other database/schema (bug SF-694)
Fix blocking of concurrent instances in PHP >7.2 (bug SF-703)
MySQL: Speed up displaying tables in large databases (bug SF-700, regression from 4.7.2)
MySQL: Allow editing rows identified by negative floats (bug SF-695)
MySQL: Skip editing generated columns
SQLite: Quote strings stored in integer columns in export (bug #696)
SQLite: Handle error in altering table (bug #697)
SQLite: Quote strings stored in integer columns in export (bug SF-696)
SQLite: Handle error in altering table (bug SF-697)
SQLite: Allow setting auto increment for empty tables
SQLite: Preserve auto increment when recreating table
MS SQL: Support foreign keys to other DB
MongoDB: Allow setting authSource from environment variable
Adminer 4.7.2 (released 2019-07-18):
Do not attempt logging in without password (bug #676)
Stretch footer over the whole table width (bug #624)
Do not attempt logging in without password (bug SF-676)
Stretch footer over the whole table width (bug SF-624)
Allow overwriting tables when copying them
Fix displaying SQL command after Save and continue edit
Cache busting for adminer.css
MySQL: Fix displaying multi-columns foreign keys (bug #675, regression from 4.7.0)
MySQL: Fix creating users and changing password in MySQL 8 (bug #663)
MySQL: Fix displaying multi-columns foreign keys (bug SF-675, regression from 4.7.0)
MySQL: Fix creating users and changing password in MySQL 8 (bug SF-663)
MySQL: Pass SRID to GeomFromText
PostgreSQL: Fix setting column comments on new table
PostgreSQL: Display definitions of materialized views (bug #682)
PostgreSQL: Fix table status in PostgreSQL 12 (bug #683)
PostgreSQL: Display definitions of materialized views (bug SF-682)
PostgreSQL: Fix table status in PostgreSQL 12 (bug SF-683)
MS SQL: Support comments
Elasticsearch: Fix setting number of rows
Adminer 4.7.1 (released 2019-01-24):
Display the tables scrollbar (bug #647)
Remember visible columns in Create Table form (bug #493)
Display the tables scrollbar (bug SF-647)
Remember visible columns in Create Table form (bug SF-493)
Add autocomplete attributes to login form
PHP <5.4 compatibility even with ClickHouse enabled (regression from 4.7.0)
SQLite: Hide server field in login form
Editor: Allow disabling boolean fields in PostgreSQL (bug #640)
Editor: Allow disabling boolean fields in PostgreSQL (bug SF-640)
Adminer 4.7.0 (released 2018-11-24):
Simplify storing executed SQL queries to bookmarks
@@ -295,16 +308,16 @@ Warn when using password with leading or trailing spaces
Hide import from server if importServerPath() returns an empty string
Fix inline editing of empty cells (regression from 4.6.3)
Allow adding more than two indexes and forign key columns at a time (regression from 4.4.0)
Avoid overwriting existing tables when copying tables (bug #642)
Avoid overwriting existing tables when copying tables (bug SF-642)
Fix function change with set data type
Increase username maxlength to 80 (bug #623)
Increase username maxlength to 80 (bug SF-623)
Make maxlength in all fields a soft limit
Make tables horizontally scrollable
MySQL: Support foreign keys created with ANSI quotes (bug #620)
MySQL: Recognize ON UPDATE current_timestamp() (bug #632, bug #638)
MySQL: Descending indexes in MySQL 8 (bug #643)
PostgreSQL: Quote array values in export (bug #621)
PostgreSQL: Export DESC indexes (bug #639)
MySQL: Support foreign keys created with ANSI quotes (bug SF-620)
MySQL: Recognize ON UPDATE current_timestamp() (bug SF-632, bug SF-638)
MySQL: Descending indexes in MySQL 8 (bug SF-643)
PostgreSQL: Quote array values in export (bug SF-621)
PostgreSQL: Export DESC indexes (bug SF-639)
PostgreSQL: Support GENERATED BY DEFAULT AS IDENTITY in PostgreSQL 10
MS SQL: Pass database when connecting
ClickHouse: Connect, databases list, tables list, select, SQL command
@@ -316,26 +329,26 @@ Copy triggers when copying table
Stop session before connecting
Simplify running slow queries
Decrease timeout for running slow queries from 5 seconds to 2 seconds
Fix displaying info about non-alphabetical objects (bug #599)
Fix displaying info about non-alphabetical objects (bug SF-599)
Use secure cookies on HTTP if session.cookie_secure is set
PDO: Support binary fields download
MySQL: Disallow LOAD DATA LOCAL INFILE
MySQL: Use CONVERT() only when searching for non-ASCII (bug #603)
MySQL: Order database names in MySQL 8 (bug #613)
PostgreSQL: Fix editing data in views (bug #605, regression from 4.6.0)
PostgreSQL: Do not cast date/time/number/uuid searches to text (bug #608)
PostgreSQL: Export false as 0 in PDO (bug #619)
MySQL: Use CONVERT() only when searching for non-ASCII (bug SF-603)
MySQL: Order database names in MySQL 8 (bug SF-613)
PostgreSQL: Fix editing data in views (bug SF-605, regression from 4.6.0)
PostgreSQL: Do not cast date/time/number/uuid searches to text (bug SF-608)
PostgreSQL: Export false as 0 in PDO (bug SF-619)
MS SQL: Support port with sqlsrv
Editor: Do not check boolean checkboxes with false in PostgreSQL (bug #607)
Editor: Do not check boolean checkboxes with false in PostgreSQL (bug SF-607)
Adminer 4.6.2 (released 2018-02-20):
Semi-transparent border on table actions
Shorten JSON values in select (bug #594)
Shorten JSON values in select (bug SF-594)
Speed up alter table form (regression from 4.4.0)
Store current version without authentication and in Editor
PostgreSQL: Fix exporting string default values
PostgreSQL: Fix exporting sequences in PostgreSQL 10
PostgreSQL: Add IF EXISTS to DROP SEQUENCE in export (bug #595)
PostgreSQL: Add IF EXISTS to DROP SEQUENCE in export (bug SF-595)
Editor: Fix displaying of true boolean values (regression from 4.5.0)
Adminer 4.6.1 (released 2018-02-09):
@@ -344,12 +357,12 @@ Speed up rendering of long tables (regression from 4.4.0)
Display notification about performing action after relogin
Add system tables help links
MySQL: Support non-utf8 charset in search in column
MySQL: Support geometry in MySQL 8 (bug #574)
MySQL: Support geometry in MySQL 8 (bug SF-574)
MariaDB: Links to documentation
SQLite: Allow deleting PRIMARY KEY from tables with auto increment
PostgreSQL: Support binary files in bytea fields
PostgreSQL: Don't treat interval type as number (bug #474)
PostgreSQL: Cast to string when searching using LIKE (bug #325)
PostgreSQL: Don't treat interval type as number (bug SF-474)
PostgreSQL: Cast to string when searching using LIKE (bug SF-325)
PostgreSQL: Fix condition for selecting no rows
PostgreSQL: Support TRUNCATE+INSERT export
Customization: Support connecting to MySQL via SSL
@@ -370,34 +383,34 @@ MySQL: Add FIND_IN_SET search operator
MariaDB: Support JSON since MariaDB 10.2
SQLite, PostgreSQL: Limit rows in data manipulation without unique key
PostgreSQL: Support routines
PostgreSQL: Allow editing views with uppercase letters (bug #467)
PostgreSQL: Allow now() as default value (bug #525)
PostgreSQL: Allow editing views with uppercase letters (bug SF-467)
PostgreSQL: Allow now() as default value (bug SF-525)
SimpleDB: Document that allow_url_fopen is required
Malay translation
Adminer 4.5.0 (released 2018-01-24):
Display name of the object in confirmation when dropping it
Display newlines in column comments (bug #573)
Support current_timestamp() as default of time fields (bug #572)
Hide window.opener from pages opened in a new window (bug #561)
Display newlines in column comments (bug SF-573)
Support current_timestamp() as default of time fields (bug SF-572)
Hide window.opener from pages opened in a new window (bug SF-561)
Display error when getting row to edit
Store current Adminer version server-side to avoid excessive requests
Adminer: Fix Search data in tables (regression from 4.4.0)
CSP: Allow any styles, images, media and fonts, disallow base-uri
MySQL: Support geometry in MySQL 8 (bug #574)
MySQL: Support routines with comments in parameters (bug #460)
MariaDB: Support fulltext and spatial indexes in InnoDB (bug #583)
MySQL: Support geometry in MySQL 8 (bug SF-574)
MySQL: Support routines with comments in parameters (bug SF-460)
MariaDB: Support fulltext and spatial indexes in InnoDB (bug SF-583)
SQLite: Enable foreign key checks
PostgreSQL: Respect NULL default value
PostgreSQL: Display foreign tables (bug #576)
PostgreSQL: Display foreign tables (bug SF-576)
PostgreSQL: Do not export triggers if not requested
PostgreSQL: Export DROP SEQUENCE if dropping table
PostgreSQL: Display boolean values as code (bug #562)
PostgreSQL: Display boolean values as code (bug SF-562)
MS SQL: Support freetds
non-MySQL: Avoid CONVERT() (bug #509)
non-MySQL: Avoid CONVERT() (bug SF-509)
Elasticsearch: Insert, update, delete
MongoDB: Support mongodb PHP extension
Editor: Fix displaying of false values in PostgreSQL (bug #568)
Editor: Fix displaying of false values in PostgreSQL (bug SF-568)
Adminer 4.4.0 (released 2018-01-17):
Add Content Security Policy
@@ -417,7 +430,7 @@ Customization: Always send security headers
Hebrew translation
Adminer 4.3.1 (released 2017-04-14):
Fix permanent login after logout (bug #539)
Fix permanent login after logout (bug SF-539)
Fix SQL command autofocus (regression from 4.0.0)
PostgreSQL: Support JSON and JSONB data types
PostgreSQL: Fix index size computation in PostgreSQL < 9.0 (regression from 4.3.0)
@@ -464,16 +477,16 @@ MySQL: Use utf8mb4 in export only if required
SQLite: Use EXPLAIN QUERY PLAN in SQL query
Adminer 4.2.0 (released 2015-02-07):
Fix XSS in login form (bug #436)
Fix XSS in login form (bug SF-436)
Allow limiting number of displayed rows in SQL command
Fix reading routine column collations
Unlock session in alter database
Make master key unreadable to others (bug #410)
Make master key unreadable to others (bug SF-410)
Fix edit by long non-utf8 string
Specify encoding for PHP 5.6 with invalid default_charset
Fix saving NULL value, bug since Adminer 4.0.3
Send 403 for auth error
Report offline and other AJAX errors (bug #419)
Report offline and other AJAX errors (bug SF-419)
Don't alter table comment if not changed
Add links to documentation on table status page
Fix handling of 64 bit numbers in auto_increment
@@ -481,7 +494,7 @@ Add referrer: never meta tag
MySQL: Use utf8mb4 if available
MySQL: Support foreign keys in NDB storage
PostgreSQL: Materialized views
SQLite: Support CURRENT_* default values (bug #417)
SQLite: Support CURRENT_* default values (bug SF-417)
Elasticsearch: Use where in select
Firebird: Alpha version
Danish translation
@@ -494,9 +507,9 @@ Display edit form after error in clone or multi-edit
Trim trailing non-breaking spaces in SQL textarea
Display time of the select command
Print elapsed time in HTML instead of SQL command comment
Improve gzip export ratio (bug #387)
Improve gzip export ratio (bug SF-387)
Use rel="noreferrer" for external links, skip adminer.org redirect in WebKit
MySQL: Fix enum types in routines (bug #391)
MySQL: Fix enum types in routines (bug SF-391)
MySQL: Fix editing rows by binary values, bug since Adminer 3.7.1
MySQL: Respect daylight saving time in dump, bug since Adminer 3.6.4
MySQL 5.6.5+: Support ON UPDATE on datatime column
@@ -564,7 +577,7 @@ Adminer 3.7.1 (released 2013-06-29):
Increase click target for checkboxes
Use shadow for highlighting default button
Don't use LIMIT 1 if inline updating unique row
Don't check previous checkbox on added column in create table (bug #326)
Don't check previous checkbox on added column in create table (bug SF-326)
Order table list by name
Verify UTF-8 encoding of CSV import
Notify user about expired master password for permanent login
@@ -575,7 +588,7 @@ Display error on invalid alter table and view pages
MySQL: Speed up updating rows without numeric or UTF-8 primary key
Non-MySQL: Descending indexes
PostgreSQL: Fix detecting oid column in PDO
PostgreSQL: Handle timestamp types (bug #324)
PostgreSQL: Handle timestamp types (bug SF-324)
Korean translation
Adminer 3.7.0 (released 2013-05-19):
@@ -588,17 +601,17 @@ Disable SQL export when applying functions in select
Allow using lang() in plugins (customization)
Remove bzip2 compression support
Constraint memory used in TAR export
Allow exporting views dependent on each other (bug #214)
Fix resetting search (bug #318)
Don't use LIMIT 1 if updating unique row (bug #320)
Allow exporting views dependent on each other (bug SF-214)
Fix resetting search (bug SF-318)
Don't use LIMIT 1 if updating unique row (bug SF-320)
Restrict editing rows without unique identifier to search results
Display navigation below main content on mobile browsers
Get number of rows on export page asynchronously
Respect 'whole result' even if some rows are checked (bug #339 since Adminer 3.7.0)
Respect 'whole result' even if some rows are checked (bug SF-339 since Adminer 3.7.0)
MySQL: Optimize create table page and Editor navigation
MySQL: Display bit type as binary number
MySQL: Improve export of binary data types
MySQL: Fix handling of POINT data type (bug #282)
MySQL: Fix handling of POINT data type (bug SF-282)
MySQL: Don't export binary and geometry columns twice in select
MySQL: Fix EXPLAIN in MySQL < 5.1, bug since Adminer 3.6.4
SQLite: Export views
@@ -613,11 +626,11 @@ Recover original view, trigger, routine if creating fails
Do not store plain text password to history in creating user
Selectable ON UPDATE CURRENT_TIMESTAMP field in create table
Open database to a new window after selecting it with Ctrl
Clear column name after resetting search (bug #296)
Explain partitions in SQL query (bug #294)
Allow loading more data with inline edit (bug #299)
Stay on the same page after deleting rows (bug #301)
Respect checked tables in export filename (bug #133)
Clear column name after resetting search (bug SF-296)
Explain partitions in SQL query (bug SF-294)
Allow loading more data with inline edit (bug SF-299)
Stay on the same page after deleting rows (bug SF-301)
Respect checked tables in export filename (bug SF-133)
Respect PHP configuration max_input_vars
Fix unsetting permanent login after logout
Disable autocapitalize in identifiers on mobile browsers
@@ -702,11 +715,11 @@ Ukrainian translation
Bengali translation
Adminer 3.3.4 (released 2012-03-07):
Foreign keys default actions (bug #188)
Foreign keys default actions (bug SF-188)
SET DEFAULT foreign key action
Fix minor parser bug in SQL command with webserver file
Ctrl+click on button opens form to a blank window
Trim table and column names (bug #195)
Trim table and column names (bug SF-195)
Error message with no response from server in AJAX
Esc to cancel AJAX request
Move AJAX loading indicator to the right
@@ -718,9 +731,9 @@ Ability to disable export (customization)
Extensible list of databases (customization)
MySQL: set autocommit after connect
SQLite, PostgreSQL: vacuum
SQLite, PostgreSQL: don't use LIKE for numbers (bug #202)
SQLite, PostgreSQL: don't use LIKE for numbers (bug SF-202)
PostgreSQL: fix alter foreign key
PostgreSQL over PDO: connect if the eponymous database does not exist (bug #185)
PostgreSQL over PDO: connect if the eponymous database does not exist (bug SF-185)
Boolean search (Editor)
Persian translation
@@ -748,8 +761,8 @@ Adminer 3.3.0 (released 2011-07-19):
Use Esc to disable in-place edit
Shortcut for database privileges
Editable index names
Append new index with auto index selection (bug #138)
Preserve original timestamp value in multiple update (bug #158)
Append new index with auto index selection (bug SF-138)
Preserve original timestamp value in multiple update (bug SF-158)
Bit type default value
Display foreign key name in tooltip
Display default column value in table overview
@@ -763,7 +776,7 @@ Display foreign keys from other schemas (PostgreSQL)
Pagination support (Oracle)
Autocomplete for big foreign keys (Editor)
Display name of the referenced record in PostgreSQL (Editor)
Prefer NULL to empty string (Editor, bug #162)
Prefer NULL to empty string (Editor, bug SF-162)
Display searched columns (Editor)
Customizable favicon (customization)
Method name can return a link (customization)
@@ -775,8 +788,8 @@ Fix AJAX history after reload
Adminer 3.2.1 (released 2011-03-23):
Ability to save expression in edit
Respect default database collation (bug #119)
Don't export triggers without table (bug #123)
Respect default database collation (bug SF-119)
Don't export triggers without table (bug SF-123)
Esc to focus next field in Tab textarea
Send forms by Ctrl+Enter on <select>
Enum editor and textarea Ctrl+Enter working in IE
@@ -799,8 +812,8 @@ Get long texts and slow information by AJAX
Most links and forms by AJAX in browsers with support for history.pushState
Copy tables
Ability to search by expression in select
Export SQL command result (bug #99)
Focus first field with insert (bug #106)
Export SQL command result (bug SF-99)
Focus first field with insert (bug SF-106)
Permanent link in schema
Display total time in show only errors mode in SQL command
History: edit all
@@ -813,7 +826,7 @@ Utilize oids in PostgreSQL
Homepage customization
Use IN for search in numeric fields (Editor)
Use password input for _md5 and _sha1 fields (Editor)
Work without session.use_cookies (bug #107)
Work without session.use_cookies (bug SF-107)
Fix saving schema to cookie in Opera
Portuguese, Slovenian and Turkish translation
@@ -826,10 +839,10 @@ Recognize $$ strings in SQL command (PostgreSQL)
Highlight and edit SQL command in processlist
Always display all drivers
Timestamp at the end of export
Link to refresh database cache (bug #96)
Link to refresh database cache (bug SF-96)
Support for virtual foreign keys
Disable XSS "protection" of IE8
Immunity against zend.ze1_compatibility_mode (bug #86)
Immunity against zend.ze1_compatibility_mode (bug SF-86)
Fix last page with empty result set
Arabic translation and RTL support
Dual licensing: Apache or GPL
@@ -877,7 +890,7 @@ Add Drop button to Alter pages (regression from 2.0.0)
Link COUNT(*) result to listing
Newlines in select query edit
Return to referrer after edit
Respect session.auto_start (bug #42)
Respect session.auto_start (bug SF-42)
Adminer 2.3.0 (released 2010-02-26):
Support for permanent login (customization required)
@@ -906,7 +919,7 @@ Link URLs in select
Display number of manipulated rows in JS confirm
Set required memory in SQL command
Fix removed default in ALTER
Display whitespace in texts (bug #11)
Display whitespace in texts (bug SF-11)
ClickJacking protection in modern browsers
E-mail attachments (Editor)
Optional year in date (Editor)
@@ -925,7 +938,7 @@ Use ON DUPLICATE KEY UPDATE for CSV import
Print ALTER export instead of executing it
Click on row selects it
Fix Editor date format
Fix long SQL query crash (bug #3)
Fix long SQL query crash (bug SF-3)
Speed up simple alter table
Traditional Chinese translation
@@ -981,7 +994,7 @@ Use \n in SQL commands
phpMinAdmin 1.10.1 (released 2009-05-07):
Highlight odd and hover rows
Partition editing comfort (bug #12)
Partition editing comfort (bug SF-12)
Allow full length in limited int
phpMinAdmin 1.10.0 (released 2009-04-28):
@@ -989,7 +1002,7 @@ Partitioning (MySQL 5.1)
CSV import
Plus and minus functions
Option to stop on error in SQL command
Cross links to select and table (bug #5), link new item
Cross links to select and table (bug SF-5), link new item
Suhosin compatibility
Remove max_allowed_packet from export
Read style from phpMinAdmin.css if exists
@@ -1068,7 +1081,7 @@ phpMinAdmin 1.4.0 (released 2007-08-15):
Privileges
New design
Dutch translation
Use NULL for auto_increment (bug #1)
Use NULL for auto_increment (bug SF-1)
Fix dropping procedure parameters
phpMinAdmin 1.3.2 (released 2007-08-06):

View File

@@ -2,8 +2,12 @@
<?php
include __DIR__ . "/adminer/include/version.inc.php";
include __DIR__ . "/adminer/include/errors.inc.php";
include __DIR__ . "/php_shrink.inc.php";
include __DIR__ . "/externals/JsShrink/jsShrink.php";
include __DIR__ . "/externals/PhpShrink/phpShrink.php";
function add_apo_slashes($s) {
return addcslashes($s, "\\'");
}
function add_quo_slashes($s) {
$return = $s;
@@ -33,31 +37,16 @@ function lang_ids($match) {
}
function put_file($match) {
global $project, $VERSION, $driver;
global $project, $vendor;
if (basename($match[2]) == '$LANG.inc.php') {
return $match[0]; // processed later
}
$return = file_get_contents(__DIR__ . "/$project/$match[2]");
$return = preg_replace('~namespace Adminer;\s*~', '', $return);
if (basename($match[2]) == "file.inc.php") {
$return = str_replace("\n// caching headers added in compile.php", (preg_match('~-dev$~', $VERSION) ? '' : '
if ($_SERVER["HTTP_IF_MODIFIED_SINCE"]) {
header("HTTP/1.1 304 Not Modified");
exit;
}
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 365*24*60*60) . " GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: immutable");
'), $return, $count);
if (!$count) {
echo "adminer/file.inc.php: Caching headers placeholder not found\n";
}
}
if ($driver && preg_match('~/drivers/~', $match[2])) {
$return = preg_replace('~^if \(isset\(\$_GET\["' . $driver . '"]\)\) \{(.*)^}~ms', '\1', $return);
if ($vendor && preg_match('~/drivers/~', $match[2])) {
$return = preg_replace('~^if \(isset\(\$_GET\["' . $vendor . '"]\)\) \{(.*)^}~ms', '\1', $return);
// check function definition in drivers
if ($driver != "mysql") {
if ($vendor != "mysql") {
preg_match_all(
'~\bfunction ([^(]+)~',
preg_replace('~class Driver.*\n\t}~sU', '', file_get_contents(__DIR__ . "/adminer/drivers/mysql.inc.php")),
@@ -85,10 +74,10 @@ header("Cache-Control: immutable");
}
}
}
unset($functions["__construct"], $functions["__destruct"], $functions["set_charset"]);
unset($functions["__construct"], $functions["__destruct"], $functions["set_charset"], $functions["fetch_column"]);
foreach ($functions as $val) {
if (!strpos($return, "$val(")) {
fprintf(STDERR, "Missing $val in $driver\n");
fprintf(STDERR, "Missing $val in $vendor\n");
}
}
}
@@ -117,7 +106,7 @@ header("Cache-Control: immutable");
function lang(\$translation, \$number = null) {
if (is_array(\$translation)) {
\$pos = $match2[2]\t\t\t: " . (preg_match("~\\\$LANG == '$_SESSION[lang]'.* \\? (.+)\n~U", $match2[1], $match3) ? $match3[1] : "1") . '
\$pos = $match2[2]\t\t\t: " . (preg_match("~'$_SESSION[lang]'.* \\? (.+)\n~U", $match2[1], $match3) ? $match3[1] : "1") . '
);
$translation = $translation[$pos];
}
@@ -253,13 +242,13 @@ if ($_SERVER["argv"][1] == "editor") {
array_shift($_SERVER["argv"]);
}
$driver = "";
$vendor = "";
$driver_path = "/adminer/drivers/" . $_SERVER["argv"][1] . ".inc.php";
if (!file_exists(__DIR__ . $driver_path)) {
$driver_path = "/plugins/drivers/" . $_SERVER["argv"][1] . ".php";
}
if (file_exists(__DIR__ . $driver_path)) {
$driver = $_SERVER["argv"][1];
$vendor = $_SERVER["argv"][1];
array_shift($_SERVER["argv"]);
}
@@ -279,12 +268,13 @@ if ($_SERVER["argv"][1]) {
include __DIR__ . "/adminer/include/pdo.inc.php";
include __DIR__ . "/adminer/include/driver.inc.php";
$connection = new stdClass; // used in support()
$features = array("check", "call" => "routine", "dump", "event", "privileges", "procedure" => "routine", "processlist", "routine", "scheme", "sequence", "status", "trigger", "type", "user" => "privileges", "variables", "view");
$lang_ids = array(); // global variable simplifies usage in a callback function
$file = file_get_contents(__DIR__ . "/$project/index.php");
$file = preg_replace('~\*/~', "* @version $VERSION\n*/", $file, 1);
if ($driver) {
$_GET[$driver] = true; // to load the driver
if ($vendor) {
$_GET[$vendor] = true; // to load the driver
include_once __DIR__ . $driver_path;
foreach ($features as $key => $feature) {
if (!Adminer\support($feature)) {
@@ -300,36 +290,39 @@ if ($driver) {
}
$file = preg_replace_callback('~\b(include|require) "([^"]*)";~', 'put_file', $file);
$file = str_replace('include "../adminer/include/coverage.inc.php";', '', $file);
if ($driver) {
if ($vendor) {
if (preg_match('~^/plugins/~', $driver_path)) {
$file = preg_replace('((include "..)/adminer/drivers/mysql.inc.php)', "\\1$driver_path", $file);
}
$file = preg_replace('(include "../adminer/drivers/(?!' . preg_quote($driver) . '\.).*\s*)', '', $file);
$file = preg_replace('(include "../adminer/drivers/(?!' . preg_quote($vendor) . '\.).*\s*)', '', $file);
}
$file = preg_replace_callback('~\b(include|require) "([^"]*)";~', 'put_file', $file); // bootstrap.inc.php
if ($driver) {
if ($vendor) {
foreach ($features as $feature) {
if (!Adminer\support($feature)) {
$file = preg_replace("((\t*)" . preg_quote('if (support("' . $feature . '")') . ".*?\n\\1\\}( else)?)s", '', $file);
}
}
if (count($drivers) == 1) {
$file = str_replace('html_select("auth[driver]", $drivers, DRIVER, "loginDriver(this);")', "\"<input type='hidden' name='auth[driver]' value='" . ($driver == "mysql" ? "server" : $driver) . "'>" . reset($drivers) . "\"", $file, $count);
if (!$count && $project != "editor") {
if ($project != "editor" && count($drivers) == 1) {
$file = str_replace('html_select("auth[driver]", $drivers, DRIVER, "loginDriver(this);")', "\"<input type='hidden' name='auth[driver]' value='" . ($vendor == "mysql" ? "server" : $vendor) . "'>" . reset($drivers) . "\"", $file, $count);
if (!$count) {
echo "auth[driver] form field not found\n";
}
$file = str_replace(" . script(\"qs('#username').form['auth[driver]'].onchange();\")", "", $file);
if ($vendor == "sqlite") {
$file = str_replace(");\n\t\techo \$this->loginFormField('server', '<tr><th>' . lang('Server') . '<td>', '<input name=\"auth[server]", ' . \'<input type="hidden" name="auth[server]"', $file);
}
}
$file = preg_replace('(;\s*../externals/jush/modules/jush-(?!textarea\.|txt\.|js\.|' . preg_quote($driver == "mysql" ? "sql" : $driver) . '\.)[^.]+.js)', '', $file);
$file = preg_replace_callback('~doc_link\(array\((.*)\)\)~sU', function ($match) use ($driver) {
$file = preg_replace('(;\s*../externals/jush/modules/jush-(?!textarea\.|txt\.|js\.|' . preg_quote($vendor == "mysql" ? "sql" : $vendor) . '\.)[^.]+.js)', '', $file);
$file = preg_replace_callback('~doc_link\(array\((.*)\)\)~sU', function ($match) use ($vendor) {
list(, $links) = $match;
$links = preg_replace("~'(?!(" . ($driver == "mysql" ? "sql|mariadb" : $driver) . ")')[^']*' => [^,]*,?~", '', $links);
$links = preg_replace("~'(?!(" . ($vendor == "mysql" ? "sql|mariadb" : $vendor) . ")')[^']*' => [^,]*,?~", '', $links);
return (trim($links) ? "doc_link(array($links))" : "''");
}, $file);
//! strip doc_link() definition
}
if ($project == "editor") {
$file = preg_replace('~;.\.\/externals/jush/jush\.css~', '', $file);
$file = preg_replace('~;.\.\/externals/jush/jush(-dark)?\.css~', '', $file);
$file = preg_replace('~compile_file\(\'\.\./(externals/jush/modules/jush\.js|adminer/static/[^.]+\.gif)[^)]+\)~', "''", $file);
}
$file = preg_replace_callback("~lang\\('((?:[^\\\\']+|\\\\.)*)'([,)])~s", 'lang_ids', $file);
@@ -343,15 +336,17 @@ if ($_SESSION["lang"]) {
}
$file = str_replace('echo script_src("static/editing.js");' . "\n", "", $file); // merged into functions.js
$file = preg_replace('~\s+echo script_src\("\.\./externals/jush/modules/jush-(textarea|txt|js|" \. JUSH \. ")\.js"\);~', '', $file); // merged into jush.js
$file = str_replace('<link rel="stylesheet" href="../externals/jush/jush.css">' . "\n", "", $file); // merged into default.css
$file = preg_replace('~echo .*/jush(-dark)?.css\'>.*~', '', $file); // merged into default.css or dark.css
$file = preg_replace_callback("~compile_file\\('([^']+)'(?:, '([^']*)')?\\)~", 'compile_file', $file); // integrate static files
$replace = 'preg_replace("~\\\\\\\\?.*~", "", ME) . "?file=\1&version=' . $VERSION . '"';
$file = preg_replace('~\.\./adminer/static/(default\.css|favicon\.ico)~', '<?php echo h(' . $replace . '); ?>', $file);
$file = preg_replace('~\.\./adminer/static/(default\.css)~', '<?php echo h(' . $replace . '); ?>', $file);
$file = preg_replace('~"\.\./adminer/static/(functions\.js)"~', $replace, $file);
$file = preg_replace('~\.\./adminer/static/([^\'"]*)~', '" . h(' . $replace . ') . "', $file);
$file = preg_replace('~"\.\./externals/jush/modules/(jush\.js)"~', $replace, $file);
$file = php_shrink($file);
if (function_exists('phpShrink')) {
$file = phpShrink($file);
}
$filename = $project . (preg_match('~-dev$~', $VERSION) ? "" : "-$VERSION") . ($driver ? "-$driver" : "") . ($_SESSION["lang"] ? "-$_SESSION[lang]" : "") . ".php";
$filename = $project . (preg_match('~-dev$~', $VERSION) ? "" : "-$VERSION") . ($vendor ? "-$vendor" : "") . ($_SESSION["lang"] ? "-$_SESSION[lang]" : "") . ".php";
file_put_contents($filename, $file);
echo "$filename created (" . strlen($file) . " B).\n";

View File

@@ -23,7 +23,7 @@ function xhtml_open_tags($s) {
return $return;
}
$coverage_filename = sys_get_temp_dir() . "/adminer_coverage.ser";
$coverage_filename = sys_get_temp_dir() . "/adminer.coverage";
if (!extension_loaded("xdebug")) {
echo "<p class='error'>Xdebug has to be enabled.\n";
} elseif ($_GET["coverage"] === "0") {

View File

@@ -1,259 +0,0 @@
/*
* Dark Theme for Adminer by 'Muhammad Bilal Yameen' [github.com/bilal-yameen/dark-theme-for-adminer]
*/
html,body,header,footer,aside,menu,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;outline:0;border:none;background:transparent;font-size:10pt;font-weight:normal}
ol,ul{list-style:none}
blockquote,q{quotes:none}
blockquote:before,blockquote:after,q:before,q:after{content:none}
:focus{outline:0}
ins{text-decoration:none}
del{text-decoration:line-through}
table{border-collapse:collapse;border-spacing:0}
aside,menu{display:block}
input[type='submit'],input[type='checkbox'],input[type='radio'],input[type='file'],select,label{cursor:pointer}
input[disabled=""]{opacity:.5;cursor:not-allowed;color:#666 !important;border-color:#aaa !important}
input[type='text']{-webkit-user-modify:read-write-plaintext-only}
@font-face{font-family:'entypo';src:url('../fonts/entypo.eot');src:url('../fonts/entypo.eot?#iefix') format('embedded-opentype'),url('../fonts/entypo.woff') format('woff'),url('../fonts/entypo.ttf') format('truetype'),url('../fonts/entypo.svg#entypo') format('svg');font-weight:normal;font-style:normal}
html{overflow-y:scroll;-webkit-text-size-adjust:none}
body{font-family:"Helvetica Neue",Helvetica,Verdana,Arial,sans-serif;background:#22252a;color:#a5a8ad;width:100%}
a,a:visited{padding:4px 0;color:#0c83d9;transition:color .1s ease 0s,background-color .1s ease 0s}
a:link:hover,a:visited:hover{color:#0063a9;text-decoration:none}
a sup{padding:0 5px}
#logins a,#tables a,#tables span{background:none}
.active:before{font-weight:normal}
label{padding:3px 10px}
input::-webkit-input-placeholder{color:#999}
input::-moz-placeholder{color:#999}
input:-ms-input-placeholder{color:#999}
input:not([type]),input[type="text"],input[type="email"],input[type="password"],input[type="search"],input[type="number"],textarea,pre[contenteditable="true"],select{padding:4px 5px !important;border:1px solid #ccc !important;border-radius:2px;font-size:10pt;background:#202225;color:#a5a8ad;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
input:not([type]),input[type="text"],input[type="email"],input[type="password"],input[type="search"],input[type="number"],textarea{-webkit-appearance:none}
input:not([type]),input[type="text"],input[type="email"],input[type="password"],input[type="search"],input[type="number"],select{height:28px}
input[type="submit"]{display:inline-block;padding:7px 15px;border:1px solid #0c83d9;border-radius:2px;background:#0c83d9;color:#fff;text-align:center;text-decoration:none;font-size:10pt;transition:background-color .1s ease 0s;-webkit-appearance:none}
input[type="submit"]:hover{background:#0063a9;border-color:#0063a9}
input[type="submit"][disabled=""]:hover{background:#22252a}
input[type="submit"].default{box-shadow:none}
input[type="image"]{border:4px solid #22252a;outline:1px solid #0a83d9;-moz-outline-radius:2px;margin-right:5px}
input[type="image"]:last-child{margin-right:0}
input[type="image"]:hover{border-color:#282b2f}
input[type="checkbox"],input[type="radio"]{margin:7px 5px 7px 0}
fieldset{margin:5px 5px 10px 0;padding:5px 10px;border:1px solid rgba(255,255,255,0.1);border-radius:2px;background:#282b2f;min-height:55px}
fieldset input[type="submit"]{padding:3px 10px;border-color:#0c83d9;background:#22252a;color:#0c83d9}
fieldset input[type="submit"]:hover{background:#0c82d4;color:#fff}
fieldset input[type="submit"].default{border-color:#0c83d9;background:#0c83d9;color:#22252a}
fieldset input[type="submit"].default:hover{background:#0063a9;border-color:#0063a9}
fieldset a{padding:6px 8px}
fieldset+table,table+fieldset{margin-top:10px}
fieldset legend a{position:relative;padding:4px 0 50px}
fieldset>div>div,fieldset>div>p,fieldset>div>a,fieldset>div>code,fieldset>div>input,fieldset>div>select,fieldset>a{position:relative}
legend{margin-bottom:3px}
legend:before,legend:after{content:" "}
p input,p select,p label,fieldset input,fieldset select{margin:0 5px 5px 0}
.js fieldset>.hidden{display:block;margin-top:5px;text-align:center}
.js fieldset>.hidden *{display:none !important}
.js fieldset>.hidden:before{content:"⏶";font-family:"entypo",sans-serif;font-size:40pt;line-height:0;vertical-align:middle;color:#e2e2e2}
#fieldset-select.hidden:before{content:"⚏"}
#fieldset-search.hidden:before{content:"🔍"}
#fieldset-sort.hidden:before{content:"⏷"}
#fieldset-export.hidden:before{content:"📤"}
#fieldset-import.hidden:before{content:"📥"}
#fieldset-history.hidden:before{content:""}
#fieldset-history br{display:block;margin-bottom:20px}
#fieldset-history.hidden br{display:none}
#fieldset-partition.hidden:before{content:""}
.size{width:8ex}
.sqlarea{width:100% !important;height:350px}
@media only screen and (max-width:768px){
input:not([type]),input[type="text"],input[type="email"],input[type="password"],input[type="search"],input[type="number"],textarea,pre[contenteditable="true"],select{font-size:12pt;vertical-align:-1px}
input:not([type]),input[type="text"],input[type="email"],input[type="password"],input[type="search"],input[type="number"],select{height:32px}
fieldset input[type="submit"]{padding:6px 15px}
.sqlarea{height:250px}
}
@media only screen and (max-width:360px){
input:not([type]),input[type="text"],input[type="email"],input[type="password"],input[type="search"],input[type="number"],textarea,pre[contenteditable="true"],select{width:100%}
input[type="submit"],fieldset input[type="submit"]{padding-left:10px;padding-right:10px}
}
#lang{position:fixed;right:0;top:0;left:auto;border:none;padding:0 0 0 10px;width:190px;height:40px;line-height:30px;font-size:0;z-index:101;background:#282b2f}
#lang select{padding:2px 3px;margin:6px 0;width:100px}
.logout{position:fixed;right:10px;margin:0;z-index:101;overflow:hidden}
.logout input[type="submit"]{border:none;margin:0;padding:0 10px;height:40px;background:transparent;color:#0c83d9}
.logout input[type="submit"]:hover{background:transparent;color:#0063a9}
@media only screen and (max-width:768px){
#lang{position:static;left:0;top:0;width:auto;border-top:1px solid rgba(255,255,255,0.1);background:#282b2f}
#lang select{margin:4px 10px 0 10px}
.logout{position:relative;float:right;margin-top:-40px}
}
@media only screen and (max-width:360px){
#lang select{margin-left:0}
}
#content{position:relative;margin:0 0 0 261px;padding:41px 20px 80px 20px}
#content:before{position:fixed;left:0;top:0;content:"";display:block;width:100%;height:40px;background:#282b2f;border-bottom:1px solid rgba(255,255,255,0.1)}
#content .links+p{color:#999}
#breadcrumb{position:fixed;left:261px;top:0;right:0;margin:0;padding:0 0 0 20px;border-right:205px solid #282b2f;background:#282b2f;height:40px;line-height:40px;z-index:100;overflow:hidden;text-overflow:ellipsis}
#breadcrumb a{display:inline-block;padding:0;height:40px;line-height:40px}
h2{margin:20px 0;font-size:20pt;color:#a5a8ad}
h3{margin:30px 0 10px 0;font-size:16pt}
p{margin:10px 0}
code{display:block;padding:10px;margin:5px 0;border-left:7px solid #58595a;border-radius:2px;background:#2d3135;overflow:auto}
td code,th code,fieldset code:first-child{display:inline;margin:0;padding:0;background:none;border:none}
pre code{margin:0}
fieldset code+i{display:none}
.time{margin-left:10px;float:right;font-size:8pt;color:#bbb}
.error,.message{margin:20px 0;padding:10px;border-left:7px solid #cec}
.error{color:#900;border-color:#ecc}
.message pre{margin:15px 0 5px 0}
.message p{margin:0 0 5px 0}
pre+.message,pre+.error{margin-top:0}
#help{z-index:200;border:1px solid rgba(255,255,255,0.1);border-radius:2px;background:#282b2f;padding:5px 7px}
.icon{background-color:#0c83d9}
.icon:hover{background-color:#0063a9}
@media only screen and (max-width:768px){
#content{margin-left:0}
#breadcrumb{left:0;padding-left:50px;border-right-width:0}
}
@media only screen and (max-width:360px){
#content{padding:41px 10px 20px}
h2{margin:15px 0;font-size:16pt}
}
h1{height:40px;white-space:nowrap;overflow:hidden}
h1 #h1{display:inline-block;padding:0;background:url("../images/logo.png?3") 10px center no-repeat;background-size:120px;text-indent:-100px;width:135px;height:40px}
.version,#version{position:relative;top:-7px;vertical-align:bottom;font-size:8pt;font-style:italic;color:#bbb}
#version{padding:5px;color:#0c83d9}
#version:hover{color:#0063a9}
#menu{position:fixed;left:0;top:0;bottom:0;width:260px;margin:0;padding:0;border-right:1px solid rgba(255,255,255,0.1);overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;background:#22252a;z-index:100}
#menu p{padding:10px;border-bottom:none}
#menu .links{background:#282b2f;border-bottom:1px solid rgba(255,255,255,0.1);padding:0 10px 7px 10px}
#menu .message{background:transparent;border:none;border-bottom:1px solid rgba(255,255,255,0.1);color:#bbb}
#filter-field{margin:0;width:100%}
.menu-list{border-bottom:1px solid rgba(255,255,255,0.1) !important;padding:0 !important;margin-bottom:25px !important }
.menu-link{display:block;padding:2px 10px;width:auto;height:20px;line-height:20px;color:#a5a8ad;overflow:hidden;text-overflow:ellipsis}
.menu-link.active{background:#282b2f;color:#0c83d9}
.menu-link.active:hover{background:#1b1f25}
p#dbs{border-top:1px solid rgba(255,255,255,0.1);background:#282b2f;color:#282b2f;font-size:0}
p#dbs span{font-size:0}
p#dbs select{margin:0;width:100%}
#tables{border-bottom:1px solid rgba(255,255,255,0.1) !important;padding:0 !important;margin-bottom:25px !important }
#tables li{position:relative}
#tables li:hover{background:#282b2f}
#tables a strong{font-weight:bold}
#tables a.structure{display:block;padding:2px 10px;width:auto;height:20px;line-height:20px;color:#a5a8ad;overflow:hidden;text-overflow:ellipsis;padding-right:0}
#tables a.structure.active{background:#282b2f;color:#0c83d9}
#tables a.structure.active:hover{background:#1b1f25}
#tables a.select{position:absolute;right:0;top:0;display:block;padding:2px 7px;height:20px;line-height:20px;color:#999;overflow:hidden;width:16px}
#tables a.select:before{content:"📄  ";font-family:entypo,sans-serif;font-size:24pt;line-height:0;vertical-align:-3px}
#tables li:first-of-type a{padding-top:7px}
#tables li:last-child a{padding-bottom:7px}
#tables a.active+a{background:#282b2f;color:#0c83d9;font-weight:bold}
#tables a.active+a:hover{background:#1b1f25}
#tables a.active:hover+a{background:#1b1f25}
#tables a:hover+a.active{background:#1b1f25}
#tables br{display:none}
#tables.simple a{display:block;padding:2px 10px;width:auto;height:20px;line-height:20px;color:#a5a8ad;overflow:hidden;text-overflow:ellipsis}
#tables.simple a.active{background:#282b2f;color:#0c83d9}
#tables.simple a.active:hover{background:#1b1f25}
#logins{border-bottom:1px solid rgba(255,255,255,0.1) !important;padding:0 !important;margin-bottom:25px !important ;border-top:1px solid rgba(255,255,255,0.1)}
#logins a{display:block;padding:2px 10px;width:auto;height:20px;line-height:20px;color:#a5a8ad;overflow:hidden;text-overflow:ellipsis}
#logins a.active{background:#282b2f;color:#0c83d9}
#logins a.active:hover{background:#1b1f25}
#logins a:hover{background:#282b2f}
#logins a:first-of-type{padding-top:7px}
#logins a:last-of-type{padding-bottom:7px}
#logins br{display:none}
@media only screen and (max-width:768px){
h1:before{float:left;position:relative;left:4px;top:4px;width:30px;height:30px;content:"☰";font-family:"entypo",sans-serif;font-size:32pt;line-height:30px;border:1px solid #0c83d9;border-radius:2px;text-align:center;vertical-align:middle;background:#22252a;cursor:pointer}
h1 #h1{margin-left:10px}
#menu{width:40px;height:40px;bottom:auto;border:none;overflow:hidden;background:transparent}
#menu form,#menu p{display:none}
#menu.open{width:260px;height:auto;max-width:100%;max-height:100%;border-right:1px solid rgba(255,255,255,0.1);border-bottom:5px solid rgba(255,255,255,0.1);background:#22252a;box-shadow:2px 2px 10px rgba(0,0,0,0.03);z-index:200;overflow-y:auto}
#menu.open form,#menu.open p{display:block}
}
@media only screen and (max-width:270px){
#menu.open{border-right:none}
}
@media only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min--moz-device-pixel-ratio:1.5),only screen and (-o-min-device-pixel-ratio:1.5),only screen and (min-device-pixel-ratio:1.5){
h1 #h1{background-image:url("../images/logo-hres.png?3");background-size:120px}
}
a[href*="&sql="]:before{content:"✎";padding:0 5px;font-family:entypo,sans-serif;font-size:24pt;line-height:10pt;vertical-align:-3px}
.links{line-height:22px}
.links a:before{content:"⏴ ";font-family:entypo,sans-serif;font-size:24pt;line-height:10pt;vertical-align:-3px}
.links a[href*="&sql="]:before{content:"";margin-left:-4px;margin-right:3px}
.links a[href*="&import="]:before{content:"📥 "}
.links a[href*="&dump="]:before{content:"📤 "}
.links a[href*="&create="]:before,.links a[href*="&db="][href*="&database="]:before,.links a[href*="&indexes="]:before{content:"✎ "}
.links a[href$="&create="]:before,.links a[href$="&database="]:before,.links a[href$="&indexes="]:before{content:" "}
.links a[href*="&schema="]:before{content:"🕪 "}
.links a[href*="&privileges="]:before{content:"👥 "}
.links a[href*="&view="]:before{content:" "}
.links a[href*="&procedure="]:before,.links a[href*="&function="]:before{content:" "}
.links a[href*="&event="]:before{content:"🔁 "}
.links a[href*="&edit="]:before{content:"⊕ "}
.links a[href*="&table="]:before{content:"⚙ "}
.links a[href*="&select="]:before{content:"📄 "}
.links a[href*="&processlist="]:before{content:" "}
.links a[href*="&status="]:before{content:"📿 "}
.links a[href*="&variables="]:before{content:" "}
.links a[href*="&user="]:before{content:" "}
.links a[href*="&foreign="]:before,.links a[href*="&trigger="]:before{content:" "}
table{border:1px solid rgba(255,255,255,0.1);margin:20px 0 10px 0}
table label.block{padding:0}
tr{border-bottom:1px dotted rgba(255,255,255,0.1)}
th,td{padding:4px 10px}
th[style="text-align: right;"] input[type="checkbox"],td[align="right"] input[type="checkbox"],th[style="text-align: right;"] input[type="radio"],td[align="right"] input[type="radio"]{margin-right:0;margin-left:5px}
thead td,thead th,.odds tbody tr:nth-child(2n),tbody tr:hover td,tbody tr:hover th,.js .checkable .checked td,.js .checkable .checked th{background:transparent}
thead tr{background:#282b2f;border-bottom:1px solid rgba(255,255,255,0.1)}
thead td,thead th{padding:7px 10px;background:transparent;text-align:left}
tbody th,tbody td{vertical-align:top}
tbody td[align="right"]{text-align:right}
tbody td[align="right"] label.block{text-align:right}
tbody th span{padding-top:4px}
table.checkable .checked{background:#282b2f}
table.checkable input[type="checkbox"],table.checkable input[type="radio"]{margin:2px 5px 2px 0}
table.checkable>thead a{padding:7px 0}
table.checkable>thead input[type="checkbox"],table.checkable>thead input[type="radio"]{margin:2px 5px 2px 0}
table.checkable>tbody>tr:hover{background:#282b2f}
table.checkable>tbody>tr.checked:hover{background:#1b1f25}
.scrollable{display:table-cell;padding-right:20px}
.loadmore{margin:0;padding:10px 0}
.footer{position:relative;padding:0}
.footer>div{padding:0}
.footer>p{position:fixed;left:261px;right:0;bottom:0;margin:0;padding:0 10px;border:none;border-top:1px solid rgba(255,255,255,0.1);background:#282b2f;z-index:102;font-weight:bold}
.footer>p a,.footer>p label{display:inline-block;margin:0;padding:0 10px;height:40px;line-height:40px}
.footer+div{line-height:36px}
.footer+div a{padding:10px 0}
.js .column{background:#22252a;padding:0;margin:-36px 0 0 -62px;border:1px solid #3e4144;border-radius:2px;z-index:10}
.js .column a{display:inline-block;padding:0;width:30px;height:30px;overflow:hidden;vertical-align:middle}
.js .column a:before{display:inline-block;width:30px;height:30px;line-height:30px;font-family:entypo,sans-serif;font-size:24pt;text-align:center;vertical-align:-3px}
.js .column a:hover:before{background:#282b2f}
.js .column a[href*='&select=']:before{content:"⬇"}
.js .column a[href='#fieldset-search']:before{content:"🔍"}
@media only screen and (max-width:768px){
.footer>p{position:static;margin:-10px 0 10px 0;border-top:none;border-left:1px solid rgba(255,255,255,0.1);border-right:1px solid rgba(255,255,255,0.1);border-bottom:1px solid rgba(255,255,255,0.1)}
.scrollable{display:block;margin:0 -20px;padding:0 20px;overflow-x:scroll}
}
a.jush-custom:hover,a.jush-help:hover{color:inherit;text-decoration:underline}
.json{border-color:#58595a;border-left:7px solid #58595a;background:#282b2f;margin:5px 0 3px 0}
.json tr{border-bottom:1px solid #58595a}
.json tr:last-child{border-bottom:none}
.json th{border-right:1px solid #58595a;vertical-align:top}
.json code{padding:4px 10px}
.json+textarea{margin-top:6px}
a.json-icon{background:transparent;text-indent:0}
a.json-icon:hover{background:transparent}
a.json-icon:before{display:inline-block;width:20px;height:18px;line-height:18px;font-family:entypo,sans-serif;font-size:24pt;vertical-align:-3px;content:"▸"}
a.json-icon.json-up{background:transparent;text-indent:0}
a.json-icon.json-up:before{content:"▾"}
a.json-link{padding-left:0}
a.json-link:before{width:10px}
a.json-link span{color:inherit}
.footer{border-image: linear-gradient(rgb(34 37 42 / 22%),#22252a) 100% 0;}
.footer > div{background: #22252a;}
.jush a {color: #1383d9;}
a.jush-custom:hover, a.jush-help:hover{color:#fff;}
.jush {color: #a5a8ad;}
.error {background: #ff00001a;color: #d8bfbf;}
.message {color: #cceecc;background: #0075001c;}
::-webkit-scrollbar {width: 10px;height: 10px;}
::-webkit-scrollbar-track {background: #3e3e3e;}
::-webkit-scrollbar-thumb {background: #888;}
::-webkit-scrollbar-thumb:hover {background: #555;}
input[type=checkbox] {display:inline-block;padding-left:25px;height:20px;outline:0;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjIwcHQiCiAgIGhlaWdodD0iNDBwdCIKICAgdmlld0JveD0iMCAwIDIwIDQwIgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJzdmcyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ4LjUgcjEwMDQwIgogICBzb2RpcG9kaTpkb2NuYW1lPSJjaGVjay5zdmciPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTE5Ij4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZGVmcwogICAgIGlkPSJkZWZzMTciIC8+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxIgogICAgIG9iamVjdHRvbGVyYW5jZT0iMTAiCiAgICAgZ3JpZHRvbGVyYW5jZT0iMTAiCiAgICAgZ3VpZGV0b2xlcmFuY2U9IjEwIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxOTIwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEwMTciCiAgICAgaWQ9Im5hbWVkdmlldzE1IgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBpbmtzY2FwZTp6b29tPSIxNiIKICAgICBpbmtzY2FwZTpjeD0iNDMuNzAyNjQ2IgogICAgIGlua3NjYXBlOmN5PSIzMS45NTE3ODMiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjE5MTIiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMiIgLz4KICA8ZwogICAgIHN0eWxlPSJmaWxsOiMwMDAwMDAiCiAgICAgaWQ9ImczMDY4IgogICAgIHRyYW5zZm9ybT0ic2NhbGUoMC44LDAuOCkiPgogICAgPHBhdGgKICAgICAgIGlkPSJwYXRoMzA1OCIKICAgICAgIGQ9Ik0gMTksNSBWIDE5IEggNSBWIDUgSCAxOSBNIDE5LDMgSCA1IEMgMy45LDMgMywzLjkgMyw1IHYgMTQgYyAwLDEuMSAwLjksMiAyLDIgaCAxNCBjIDEuMSwwIDIsLTAuOSAyLC0yIFYgNSBDIDIxLDMuOSAyMC4xLDMgMTksMyB6IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDMwNjAiCiAgICAgICBkPSJNIDAsMCBIIDI0IFYgMjQgSCAwIHoiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZSIgLz4KICA8L2c+CiAgPGcKICAgICBzdHlsZT0iZmlsbDojMDAwMDAwIgogICAgIGlkPSJnMzA4NCIKICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjgsMCwwLDAuOCwwLDIwKSI+CiAgICA8cGF0aAogICAgICAgaWQ9InBhdGgzMDc0IgogICAgICAgZD0iTSAwLDAgSCAyNCBWIDI0IEggMCB6IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmUiIC8+CiAgICA8cGF0aAogICAgICAgaWQ9InBhdGgzMDc2IgogICAgICAgZD0iTSAxOSwzIEggNSBDIDMuODksMyAzLDMuOSAzLDUgdiAxNCBjIDAsMS4xIDAuODksMiAyLDIgaCAxNCBjIDEuMTEsMCAyLC0wLjkgMiwtMiBWIDUgQyAyMSwzLjkgMjAuMTEsMyAxOSwzIHogTSAxMCwxNyA1LDEyIDYuNDEsMTAuNTkgMTAsMTQuMTcgMTcuNTksNi41OCAxOSw4IDEwLDE3IHoiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogIDwvZz4KPC9zdmc+Cg==);background-position:00;background-size:20px;background-repeat:no-repeat;vertical-align:middle;font-size:20px;line-height:20px;cursor:pointer;-webkit-appearance:none;-webkit-user-select:none;user-select:none;filter:invert();}
input[type=checkbox]:checked {background-position:0-20px;}

View File

@@ -1 +1,3 @@
Copy adminer.css alongside Adminer PHP script to use an alternative design.
If the design supports dark mode then it should be named adminer-dark.css.

View File

@@ -59,15 +59,17 @@ class Adminer {
return csp();
}
function head() {
function head($dark = null) {
return true;
}
function css() {
$return = array();
$filename = "adminer.css";
if (file_exists($filename)) {
$return[] = $filename;
foreach (array("", "-dark") as $mode) {
$filename = "adminer$mode.css";
if (file_exists($filename)) {
$return[] = "$filename?v=" . crc32(file_get_contents($filename));
}
}
return $return;
}
@@ -211,9 +213,8 @@ ORDER BY ORDINAL_POSITION", null, "") as $row //! requires MySQL 5
if ($link) {
$return = "<a href='$link'" . (is_url($link) ? target_blank() : "") . ">$return</a>";
}
if (!$link && !like_bool($field) && preg_match(number_type(), $field["type"])) {
$return = "<div class='number'>$return</div>"; // Firefox doesn't support <colgroup>
} elseif (preg_match('~date~', $field["type"])) {
// Firefox doesn't support <colgroup>
if (preg_match('~date~', $field["type"])) {
$return = "<div class='datetime'>$return</div>";
}
return $return;
@@ -626,6 +627,9 @@ qsl('div').onclick = whisperClick;", "")
}
}
function syntaxHighlighting($tables) {
}
function databasesPrint($missing) {
}

1
externals/PhpShrink vendored Submodule

Submodule externals/PhpShrink added at b6fc11da47

2
externals/jush vendored

View File

@@ -1,144 +0,0 @@
<?php
/** Minify PHP code with these operations:
* remove extra {}
* minify variables
* strip comments, preserve only the first doc-comment
* join consecutive echo
* change ?>HTML<?php to echo 'HTML' if it saves space
* strip public visibility or change it to var
*
* @param string PHP code including <?php
* @return string
*/
function php_shrink($input) {
// based on http://latrine.dgx.cz/jak-zredukovat-php-skripty
$input = preg_replace("~<\\?php\\s*\\?>\n?|\\?>\n?<\\?php~", '', $input);
$special_variables = array_flip(array('$this', '$GLOBALS', '$_GET', '$_POST', '$_FILES', '$_COOKIE', '$_SESSION', '$_SERVER', '$http_response_header', '$php_errormsg'));
$short_variables = array();
$shortening = true;
$tokens = token_get_all($input);
// remove unnecessary { }
//! change also `while () { if () {;} }` to `while () if () ;` but be careful about `if () { if () { } } else { }
$shorten = 0;
$opening = -1;
foreach ($tokens as $i => $token) {
if (in_array($token[0], array(T_IF, T_ELSE, T_ELSEIF, T_WHILE, T_DO, T_FOR, T_FOREACH), true)) {
$shorten = ($token[0] == T_FOR ? 4 : 2);
$opening = -1;
} elseif (in_array($token[0], array(T_SWITCH, T_FUNCTION, T_CLASS, T_CLOSE_TAG), true)) {
$shorten = 0;
} elseif ($token === ';') {
$shorten--;
} elseif ($token === '{') {
if ($opening < 0) {
$opening = $i;
} elseif ($shorten > 1) {
$shorten = 0;
}
} elseif ($token === '}' && $opening >= 0 && $shorten == 1) {
unset($tokens[$opening]);
unset($tokens[$i]);
$shorten = 0;
$opening = -1;
}
}
$tokens = array_values($tokens);
foreach ($tokens as $i => $token) {
if ($token[0] === T_VARIABLE && !isset($special_variables[$token[1]])) {
$short_variables[$token[1]]++;
}
}
arsort($short_variables);
$chars = implode(range('a', 'z')) . '_' . implode(range('A', 'Z'));
//! preserve variable names between versions if possible
$short_variables2 = array_splice($short_variables, strlen($chars));
ksort($short_variables);
ksort($short_variables2);
$short_variables += $short_variables2;
foreach (array_keys($short_variables) as $number => $key) {
$short_variables[$key] = short_identifier($number, $chars); // could use also numbers and \x7f-\xff
}
$set = array_flip(preg_split('//', '!"#$%&\'()*+,-./:;<=>?@[]^`{|}'));
$space = '';
$output = '';
$in_echo = false;
$doc_comment = false; // include only first /**
for (reset($tokens); list($i, $token) = each($tokens);) {
if (!is_array($token)) {
$token = array(0, $token);
}
if (
$tokens[$i+2][0] === T_CLOSE_TAG && $tokens[$i+3][0] === T_INLINE_HTML && $tokens[$i+4][0] === T_OPEN_TAG
&& strlen(add_apo_slashes($tokens[$i+3][1])) < strlen($tokens[$i+3][1]) + 3
) {
$tokens[$i+2] = array(T_ECHO, 'echo');
$tokens[$i+3] = array(T_CONSTANT_ENCAPSED_STRING, "'" . add_apo_slashes($tokens[$i+3][1]) . "'");
$tokens[$i+4] = array(0, ';');
}
if ($token[0] == T_COMMENT || $token[0] == T_WHITESPACE || ($token[0] == T_DOC_COMMENT && $doc_comment)) {
$space = "\n";
} else {
if ($token[0] == T_DOC_COMMENT) {
$doc_comment = true;
}
if ($token[0] == T_VAR || $token[0] == T_PUBLIC || $token[0] == T_PROTECTED || $token[0] == T_PRIVATE) {
if ($token[0] == T_PUBLIC) {
$token[1] = ($tokens[$i+2][1][0] == '$' ? 'var' : '');
}
$shortening = false;
} elseif (!$shortening) {
if ($token[1] == ';' || $token[0] == T_FUNCTION) {
$shortening = true;
}
} elseif ($token[0] == T_ECHO) {
$in_echo = true;
} elseif ($token[1] == ';' && $in_echo) {
if ($tokens[$i+1][0] === T_WHITESPACE && $tokens[$i+2][0] === T_ECHO) {
next($tokens);
$i++;
}
if ($tokens[$i+1][0] === T_ECHO) {
// join two consecutive echos
next($tokens);
$token[1] = ','; // '.' would conflict with "a".1+2 and would use more memory //! remove ',' and "," but not $var","
} else {
$in_echo = false;
}
} elseif ($token[0] === T_VARIABLE && !isset($special_variables[$token[1]])) {
$token[1] = '$' . $short_variables[$token[1]];
}
if (isset($set[substr($output, -1)]) || isset($set[$token[1][0]])) {
$space = '';
}
$output .= $space . $token[1];
$space = '';
}
}
return $output;
}
function short_identifier($number, $chars) {
$return = '';
while ($number >= 0) {
$return .= $chars[$number % strlen($chars)];
$number = floor($number / strlen($chars)) - 1;
}
return $return;
}
function add_apo_slashes($s) {
return addcslashes($s, "\\'");
}
if (!function_exists("each")) {
function each(&$arr) {
$key = key($arr);
next($arr);
return $key === null ? false : array($key, $arr[$key]);
}
}

View File

@@ -32,11 +32,19 @@
<exclude name="PSR12.Classes.ClassInstantiation.MissingParentheses"/>
<exclude name="Squiz.Scope.MethodScope.Missing"/>
<!-- TODO: Ignore only in <?php if () { ?><?php } ?> -->
<!-- False positives. -->
<exclude name="Generic.WhiteSpace.ScopeIndent.Incorrect"/>
<exclude name="Generic.WhiteSpace.ScopeIndent.IncorrectExact"/>
</rule>
<rule ref="Generic.WhiteSpace.ScopeIndent">
<properties>
<property name="ignoreIndentationTokens" type="array">
<element value="T_OPEN_TAG"/>
</property>
</properties>
</rule>
<rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
<exclude-pattern>adminer/drivers/</exclude-pattern>
<exclude-pattern>adminer/include/pdo.inc.php</exclude-pattern>

View File

@@ -11,7 +11,7 @@
class AdminerDotJs {
const FILENAME = "adminer.js";
function head() {
function head($dark = null) {
if (file_exists(self::FILENAME)) {
echo Adminer\script_src(self::FILENAME . "?v=" . crc32(file_get_contents(self::FILENAME))), "\n";
}

92
plugins/codemirror.php Normal file
View File

@@ -0,0 +1,92 @@
<?php
/** Use Codemirror 5 for syntax highlighting and SQL <textarea> including type-ahead of keywords and tables
* @link https://codemirror.net/5/
* @link https://www.adminer.org/plugins/#use
* @author Jakub Vrana, https://www.vrana.cz/
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
class AdminerCodemirror {
private $root;
function __construct($root = "codemirror5") {
$this->root = $root;
}
function syntaxHighlighting($tableStatuses) {
$connection = Adminer\connection();
?>
<style>
@import url(<?php echo $this->root; ?>/lib/codemirror.css);
@import url(<?php echo $this->root; ?>/addon/hint/show-hint.css);
.CodeMirror { border: 1px inset #ccc; resize: both; }
</style>
<?php
echo Adminer\script_src("$this->root/lib/codemirror.js");
echo Adminer\script_src("$this->root/addon/runmode/runmode.js");
echo Adminer\script_src("$this->root/addon/hint/show-hint.js");
echo Adminer\script_src("$this->root/mode/javascript/javascript.js");
if (Adminer\support("sql")) {
echo Adminer\script_src("$this->root/mode/sql/sql.js");
echo Adminer\script_src("$this->root/addon/hint/sql-hint.js");
}
$tables = array();
foreach ($tableStatuses as $status) {
foreach (Adminer\fields($status["Name"]) as $name => $field) {
$tables[$status["Name"]][] = $name;
}
}
?>
<script <?php echo Adminer\nonce(); ?>>
function getCmMode(el) {
const match = el.className.match(/(^|\s)jush-([^ ]+)/);
if (match) {
const modes = {
js: 'application/json',
sql: 'text/x-<?php echo ($connection->maria ? "mariadb" : "mysql"); ?>',
oracle: 'text/x-sql',
clickhouse: 'text/x-sql',
firebird: 'text/x-sql'
};
return modes[match[2]] || 'text/x-' + match[2];
}
}
for (const el of qsa('code')) {
const mode = getCmMode(el);
if (mode) {
el.className += ' cm-s-default';
CodeMirror.runMode(el.textContent, mode, el);
}
}
for (const el of qsa('textarea')) {
const mode = getCmMode(el);
if (mode) {
const width = el.clientWidth;
const height = el.clientHeight;
const cm = CodeMirror.fromTextArea(el, {
mode: mode,
extraKeys: { 'Ctrl-Space': 'autocomplete' },
hintOptions: {
completeSingle: false,
tables: <?php echo json_encode($tables); ?>,
defaultTable: <?php echo json_encode($_GET["trigger"] ? $_GET["trigger"] : ($_GET["check"] ? $_GET["check"] : null)); ?>
}
});
cm.setSize(width, height);
cm.on('inputRead', function () {
const token = cm.getTokenAt(cm.getCursor());
if (/^[.`"\w]\w*$/.test(token.string)) {
CodeMirror.commands.autocomplete(cm);
}
});
setupSubmitHighlightInput(cm.getWrapperElement());
}
}
</script>
<?php
return true;
}
}

View File

@@ -61,7 +61,7 @@ if (isset($_GET["elastic"])) {
function query($path, array $content = null, $method = 'GET') {
// Support for global search through all tables
if ($path != "" && $path[0] == "S" && preg_match('/SELECT 1 FROM ([^ ]+) WHERE (.+) LIMIT ([0-9]+)/', $path, $matches)) {
$driver = get_driver();
$driver = driver();
$where = explode(" AND ", $matches[2]);

View File

@@ -73,8 +73,8 @@ if (isset($_GET["mongo"])) {
(is_a($val, 'MongoDB\BSON\Binary') ? $val->getData() : //! allow downloading
(is_a($val, 'MongoDB\BSON\Regex') ? "$val" :
(is_object($val) || is_array($val) ? json_encode($val, 256) : // 256 = JSON_UNESCAPED_UNICODE
$val // MongoMinKey, MongoMaxKey
)))));
$val))))) // MongoMinKey, MongoMaxKey
;
}
$this->rows[] = $row;
foreach ($row as $key => $val) {
@@ -166,7 +166,7 @@ if (isset($_GET["mongo"])) {
}
function fields($table) {
$driver = get_driver();
$driver = driver();
$fields = fields_from_edit();
if (!$fields) {
$result = $driver->select($table, array("*"), null, null, array(), 10);

View File

@@ -27,7 +27,7 @@ class AdminerEditCalendar {
$this->langPath = $langPath;
}
function head() {
function head($dark = null) {
echo $this->prepend;
if ($this->langPath) {
$lang = Adminer\get_lang();

View File

@@ -10,19 +10,10 @@ class AdminerPlugin extends Adminer\Adminer {
protected $plugins;
/** Register plugins
* @param array object instances or null to register all classes starting by 'Adminer'
* @param array object instances
*/
function __construct($plugins) {
if ($plugins === null) {
$plugins = array();
foreach (get_declared_classes() as $class) {
if (preg_match('~^Adminer\w~i', $class) && !is_subclass_of($class, 'Adminer\Adminer')) {
$plugins[$class] = new $class;
}
}
}
$this->plugins = $plugins;
//! it is possible to use ReflectionObject to find out which plugins defines which methods at once
}
private function callParent($function, $args) {
@@ -162,7 +153,7 @@ class AdminerPlugin extends Adminer\Adminer {
return $this->applyPlugin(__FUNCTION__, $args);
}
function head() {
function head($dark = null) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
@@ -407,6 +398,11 @@ class AdminerPlugin extends Adminer\Adminer {
return $this->applyPlugin(__FUNCTION__, $args);
}
function syntaxHighlighting($tables) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);
}
function databasesPrint($missing) {
$args = func_get_args();
return $this->applyPlugin(__FUNCTION__, $args);

View File

@@ -18,7 +18,7 @@ class AdminerPrettyJsonColumn {
$json = $this->testJson($value);
if ($json !== $value) {
$jsonText = json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
return "<textarea$attrs cols='50' rows='20'>" . h($jsonText) . "</textarea>";
return "<textarea$attrs cols='50' rows='20'>" . Adminer\h($jsonText) . "</textarea>";
}
return '';
}

View File

@@ -1,14 +0,0 @@
<?php
/** Show comments of sql structure in more places (mainly where you edit things)
* @link https://www.adminer.org/plugins/#use
* @author Adam Kuśmierz, http://kusmierz.be/
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
class AdminerStructComments {
function fieldName(&$field, $order = 0) {
return '<span title="' . Adminer\h($field["full_type"]) . (!empty($field["comment"]) ? ': ' . $field["comment"] : '') . '">' . Adminer\h($field["field"]) . '</span>';
}
}

View File

@@ -17,7 +17,7 @@ class AdminerTinymce {
$this->path = $path;
}
function head() {
function head($dark = null) {
$lang = Adminer\get_lang();
$lang = ($lang == "zh" ? "zh-cn" : ($lang == "zh-tw" ? "zh" : $lang));
if (!file_exists(dirname($this->path) . "/langs/$lang.js")) {

View File

@@ -8,7 +8,7 @@
*/
class AdminerVersionNoverify {
function head() {
function head($dark = null) {
echo Adminer\script("verifyVersion = function () {};");
}
}

View File

@@ -19,7 +19,7 @@ class AdminerWymeditor {
$this->options = $options;
}
function head() {
function head($dark = null) {
foreach ($this->scripts as $script) {
echo Adminer\script_src($script);
}

View File

@@ -6,10 +6,9 @@
<title>Katalon CockroachDB</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Login</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Login</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/</td><td></td></tr>
<tr><td>select</td><td>name=lang</td><td>label=English</td></tr>
@@ -18,13 +17,12 @@
<tr><td>type</td><td>name=auth[server]</td><td>localhost:26257</td></tr>
<tr><td>type</td><td>id=username</td><td>ODBC</td></tr>
<tr><td>type</td><td>name=auth[password]</td><td>ODBC</td></tr>
<tr><td>clickAndWait</td><td>xpath=//input[@value='Login']</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Login']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>CockroachDB</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create table</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
@@ -42,10 +40,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create index</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create index</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter indexes</td><td></td></tr>
@@ -58,10 +55,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create table 2</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create table 2</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
@@ -79,10 +75,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Foreign key</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Foreign key</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;table=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Add foreign key</td><td></td></tr>
@@ -91,10 +86,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Foreign key has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Alter table</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Alter table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter table</td><td></td></tr>
@@ -108,27 +102,29 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Check constraints</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Check constraints</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;table=albums</td><td></td></tr>
<tr><td>click</td><td>link=Create check</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>albums_interpret_check</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="clause"]').value = 'interpret > 0'</td><td></td></tr>
<tr><td>click</td><td>xpath=//input[@value='Save']</td><td></td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=New item</td><td></td></tr>
<tr><td>type</td><td>fields[interpret]</td><td>0</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>failed to satisfy CHECK constraint</td><td></td></tr>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;check=albums&amp;name=albums_interpret_check</td><td></td></tr>
<tr><td>verifyTextPresent<td>((interpret > 0:::INT8))</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop albums_interpret_check?</td><td></td></tr>
<tr><td>click</td><td>name=drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create view</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create view</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;view=</td><td></td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="select"]').value = 'SELECT albums.id, albums.title, interprets.name FROM albums LEFT JOIN interprets ON albums.interpret = interprets.id'</td><td></td></tr>
@@ -136,10 +132,20 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>View has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Insert</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Materialized view</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;view=</td><td></td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="select"]').value = 'SELECT albums.id, albums.title, interprets.name FROM albums LEFT JOIN interprets ON albums.interpret = interprets.id'</td><td></td></tr>
<tr><td>type</td><td>name</td><td>materialized_view</td></tr>
<tr><td>click</td><td>materialized</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Materialized view</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Insert</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;edit=interprets</td><td></td></tr>
<tr><td>type</td><td>fields[id]</td><td>1</td></tr>
@@ -152,10 +158,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item has been inserted.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Clone</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Clone</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>check[]</td><td></td></tr>
@@ -165,10 +170,35 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>1 item has been affected.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Explain</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3" data-tags="">Enum</td></tr></thead>
<tbody>
<tr><td>open</td><td>http://localhost:8080/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public</td><td></td></tr>
<tr><td>click</td><td>link=Create type</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>alive</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="as"]').value = "AS ENUM('alive', 'deceased')"</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>click</td><td>link=interprets</td><td></td></tr>
<tr><td>click</td><td>link=Alter table</td><td></td></tr>
<tr><td>click</td><td>name=add[3]</td><td></td></tr>
<tr><td>type</td><td>name=fields[4][field]</td><td>alive</td></tr>
<tr><td>select</td><td>name=fields[4][type]</td><td>label=alive</td></tr>
<tr><td>click</td><td>name=fields[4][null]</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>click</td><td>link=alive</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>'alive', 'deceased'</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop alive?</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Drop']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>cannot drop type</td><td></td></tr>
<tr><td>open</td><td>http://localhost:8080/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;edit=interprets&amp;where%5Bid%5D=1</td><td></td></tr>
<tr><td>click</td><td>//input[@value='deceased']</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>deceased</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Explain</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Edit</td><td></td></tr>
@@ -176,29 +206,26 @@
<tr><td>click</td><td>link=Explain</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>LIMITED SCAN</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Reference</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Reference</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=1</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Michael Jackson</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Update</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Update</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;edit=albums&amp;where%5Bid%5D=2</td><td></td></tr>
<tr><td>type</td><td>fields[title]</td><td>Black or White</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item has been updated.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Delete</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Delete</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>//input[@name='check[]' and @value='where%5Bid%5D=2']</td><td></td></tr>
@@ -207,10 +234,9 @@
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>1 item has been affected.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Truncate</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Truncate</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>all</td><td></td></tr>
@@ -219,10 +245,9 @@
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>No rows.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Export</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Export</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;dump=</td><td></td></tr>
<tr><td>click</td><td>output</td><td></td></tr>
@@ -234,10 +259,9 @@
<tr><td>verifyTextPresent</td><td>INSERT INTO "interprets"</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>VIEW "albums_interprets"</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Procedures</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Procedures</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;procedure=</td><td></td></tr>
<tr><td>clickAndWait</td><td>add[0]</td><td></td></tr>
@@ -257,18 +281,41 @@
<tr><td>type</td><td>fields[album_title]</td><td>Dangerous</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Call']</td><td></td></tr>
<tr><td>assertTextPresent</td><td>Routine has been called,</td><td></td></tr>
<!-- https://github.com/cockroachdb/cockroach/issues/142886
<tr><td>clickAndWait</td><td>link=public</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop insert_album?</td><td></td></tr>
<tr><td>click</td><td>drop</td><td></td></tr>
<!-- This looks like a bug in CockroachDB, not Adminer. <tr><td>verifyTextPresent</td><td>Routine has been dropped.</td><td></td></tr> -->
<tr><td>verifyTextPresent</td><td>Routine has been dropped.</td><td></td></tr>
-->
<tr><td>open</td><td>/adminer/?pgsql=localhost%3A26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;sql=DROP+PROCEDURE+%22insert_album%22</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Execute']</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Drop</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3" data-tags="">Generated columns</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;create=</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>generated</td></tr>
<tr><td>type</td><td>name=fields[1][field]</td><td>normal</td></tr>
<tr><td>type</td><td>name=fields[1.1][field]</td><td>stored</td></tr>
<tr><td>select</td><td>name=fields[1.1][generated]</td><td>label=STORED</td></tr>
<tr><td>type</td><td>name=fields[1.1][default]</td><td>normal + 200</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>normal + 200</td><td></td></tr>
<tr><td>click</td><td>link=Alter indexes</td><td></td></tr>
<tr><td>select</td><td>name=indexes[2][columns][1]</td><td>label=stored</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
<tr><td>click</td><td>link=New item</td><td></td></tr>
<tr><td>verifyTextNotPresent</td><td>stored</td><td></td></tr>
<tr><td>type</td><td>name=fields[normal]</td><td>20</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>220</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Drop</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public</td><td></td></tr>
<tr><td>click</td><td>id=check-all</td><td></td></tr>
@@ -276,32 +323,30 @@
<tr><td>click</td><td>name=drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>No tables.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Variables</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Variables</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;variables=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>crdb_version</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">SQL command</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">SQL command</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;sql=SELECT+122%2B1</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Execute']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>123</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Logout</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Logout</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC</td><td></td></tr>
<tr><td>clickAndWait</td><td>logout</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Logout successful.</td><td></td></tr>
<tr><td>open</td><td>/coverage.php</td><td></td></tr>
</tbody></table>
</body>
</html>

View File

@@ -6,10 +6,9 @@
<title>Katalon MariaDB</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Login</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Login</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/</td><td></td></tr>
<tr><td>select</td><td>name=lang</td><td>label=English</td></tr>
@@ -17,17 +16,16 @@
<tr><td>type</td><td>id=username</td><td>ODBC</td></tr>
<tr><td>type</td><td>name=auth[server]</td><td>localhost:3307</td></tr>
<tr><td>type</td><td>name=auth[password]</td><td>ODBC</td></tr>
<tr><td>clickAndWait</td><td>xpath=//input[@value='Login']</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Login']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>MariaDB</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=SQL command</td><td></td></tr>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;sql=DROP+DATABASE+IF+EXISTS+adminer_test</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Execute']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Query executed OK</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create database</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create database</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create database</td><td></td></tr>
@@ -36,10 +34,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Database has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create table</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
@@ -58,10 +55,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create index</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create index</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter indexes</td><td></td></tr>
@@ -74,10 +70,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Partitioning</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Partitioning</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter table</td><td></td></tr>
@@ -97,10 +92,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create table 2</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create table 2</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
@@ -120,10 +114,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Foreign key</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Foreign key</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;table=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Add foreign key</td><td></td></tr>
@@ -132,10 +125,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Foreign key has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Alter table</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Alter table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter table</td><td></td></tr>
@@ -149,10 +141,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create trigger</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create trigger</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;trigger=albums</td><td></td></tr>
<tr><td>select</td><td>Timing</td><td>label=AFTER</td></tr>
@@ -160,27 +151,29 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Trigger has been created.</td><td></td></tr></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Check constraints</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Check constraints</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;table=albums</td><td></td></tr>
<tr><td>click</td><td>link=Create check</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>albums_interpret_check</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="clause"]').value = 'interpret > 0'</td><td></td></tr>
<tr><td>click</td><td>xpath=//input[@value='Save']</td><td></td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=New item</td><td></td></tr>
<tr><td>type</td><td>fields[interpret]</td><td>0</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>CONSTRAINT `albums_interpret_check` failed for `adminer_test`.`albums`</td><td></td></tr>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;check=albums&amp;name=albums_interpret_check</td><td></td></tr>
<tr><td>verifyTextPresent<td>`interpret` > 0</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop albums_interpret_check?</td><td></td></tr>
<tr><td>click</td><td>name=drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create view</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create view</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;view=</td><td></td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="select"]').value = 'SELECT albums.id, albums.title, interprets.name FROM albums LEFT JOIN interprets ON albums.interpret = interprets.id'</td><td></td></tr>
@@ -188,10 +181,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>View has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Insert</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Insert</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;edit=interprets</td><td></td></tr>
<tr><td>type</td><td>fields[name]</td><td>Michael Jackson</td></tr>
@@ -203,10 +195,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item 1 has been inserted.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Clone</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Clone</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>check[]</td><td></td></tr>
@@ -215,10 +206,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item 2 has been inserted.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Explain</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Explain</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Edit</td><td></td></tr>
@@ -226,29 +216,26 @@
<tr><td>click</td><td>link=Explain</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>possible_keys</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Reference</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Reference</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=1</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Michael Jackson</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Update</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Update</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;edit=albums&amp;where%5Bid%5D=2</td><td></td></tr>
<tr><td>type</td><td>fields[title]</td><td>Black or White</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item has been updated.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Delete</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Delete</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>//input[@name='check[]' and @value='where%5Bid%5D=2']</td><td></td></tr>
@@ -257,10 +244,9 @@
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>1 item has been affected.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Truncate</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Truncate</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>all</td><td></td></tr>
@@ -269,10 +255,9 @@
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>No rows.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Privileges</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Privileges</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;user=</td><td></td></tr>
<tr><td>type</td><td>user</td><td>adminer_test</td></tr>
@@ -298,18 +283,16 @@
<tr><td>click</td><td>drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>User has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Process list</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Process list</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;processlist=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>SHOW FULL PROCESSLIST</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Export</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Export</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;dump=</td><td></td></tr>
<tr><td>click</td><td>output</td><td></td></tr>
@@ -322,10 +305,9 @@
<tr><td>verifyTextPresent</td><td>INSERT INTO `interprets`</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>VIEW `albums_interprets`</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Events</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Events</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;event=</td><td></td></tr>
<tr><td>type</td><td>EVENT_NAME</td><td>no_albums</td></tr>
@@ -340,10 +322,9 @@
<tr><td>click</td><td>drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Event has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Procedures</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Procedures</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;procedure=</td><td></td></tr>
<tr><td>clickAndWait</td><td>add[0]</td><td></td></tr>
@@ -368,31 +349,60 @@
<tr><td>click</td><td>drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Routine has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Variables</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3" data-tags="">Generated columns</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&amp;create=</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>generated</td></tr>
<tr><td>type</td><td>name=fields[1][field]</td><td>normal</td></tr>
<tr><td>type</td><td>name=fields[1.1][field]</td><td>virtual</td></tr>
<tr><td>select</td><td>name=fields[1.1][generated]</td><td>label=VIRTUAL</td></tr>
<tr><td>type</td><td>name=fields[1.1][default]</td><td>normal + 100</td></tr>
<tr><td>type</td><td>name=fields[1.11][field]</td><td>stored</td></tr>
<tr><td>select</td><td>name=fields[1.11][generated]</td><td>label=STORED</td></tr>
<tr><td>type</td><td>name=fields[1.11][default]</td><td>normal + 200</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>`normal` + 100</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>`normal` + 200</td><td></td></tr>
<tr><td>click</td><td>link=Alter indexes</td><td></td></tr>
<tr><td>select</td><td>name=indexes[1][columns][1]</td><td>label=virtual</td></tr>
<tr><td>select</td><td>name=indexes[1][columns][11]</td><td>label=stored</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
<tr><td>click</td><td>link=New item</td><td></td></tr>
<tr><td>verifyTextNotPresent</td><td>virtual</td><td></td></tr>
<tr><td>verifyTextNotPresent</td><td>stored</td><td></td></tr>
<tr><td>type</td><td>name=fields[normal]</td><td>20</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>120</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>220</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Variables</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;variables=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>basedir</td><td></td></tr>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;status=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Uptime</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">History</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">History</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;sql=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>DROP DATABASE IF EXISTS adminer_test</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Logout</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Logout</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC</td><td></td></tr>
<tr><td>clickAndWait</td><td>logout</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Logout successful.</td><td></td></tr>
<tr><td>open</td><td>/coverage.php</td><td></td></tr>
</tbody></table>
</body>
</html>

View File

@@ -6,10 +6,9 @@
<title>Katalon MS SQL</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Login</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Login</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/</td><td></td></tr>
<tr><td>select</td><td>name=lang</td><td>label=English</td></tr>
@@ -18,12 +17,11 @@
<tr><td>type</td><td>name=auth[server]</td><td>(local)</td></tr>
<tr><td>type</td><td>id=username</td><td>ODBC</td></tr>
<tr><td>type</td><td>name=auth[password]</td><td>ODBC</td></tr>
<tr><td>clickAndWait</td><td>xpath=//input[@value='Login']</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Login']</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create table</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
@@ -41,10 +39,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create index</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create index</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter indexes</td><td></td></tr>
@@ -57,10 +54,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create table 2</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create table 2</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
@@ -78,10 +74,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Foreign key</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Foreign key</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;table=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Add foreign key</td><td></td></tr>
@@ -90,10 +85,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Foreign key has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Alter table</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Alter table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter table</td><td></td></tr>
@@ -107,27 +101,29 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Check constraints</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Check constraints</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;table=albums</td><td></td></tr>
<tr><td>click</td><td>link=Create check</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>albums_interpret_check</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="clause"]').value = 'interpret > 0'</td><td></td></tr>
<tr><td>click</td><td>xpath=//input[@value='Save']</td><td></td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=New item</td><td></td></tr>
<tr><td>type</td><td>fields[interpret]</td><td>0</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>statement conflicted with the CHECK constraint</td><td></td></tr>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;check=albums&amp;name=albums_interpret_check</td><td></td></tr>
<tr><td>verifyTextPresent<td>([interpret]>(0))</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop albums_interpret_check?</td><td></td></tr>
<tr><td>click</td><td>name=drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create view</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create view</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;view=</td><td></td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="select"]').value = 'SELECT albums.id, albums.title, interprets.name FROM albums LEFT JOIN interprets ON albums.interpret = interprets.id'</td><td></td></tr>
@@ -135,10 +131,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>View has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Insert</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Insert</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;edit=interprets</td><td></td></tr>
<tr><td>type</td><td>fields[name]</td><td>Michael Jackson</td></tr>
@@ -150,10 +145,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item 1 has been inserted.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Clone</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Clone</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>check[]</td><td></td></tr>
@@ -162,10 +156,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item 2 has been inserted.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Explain</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Explain</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Edit</td><td></td></tr>
@@ -173,29 +166,26 @@
<tr><td>click</td><td>link=Explain</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Clustered Index Scan</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Reference</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Reference</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=1</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Michael Jackson</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Update</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Update</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;edit=albums&amp;where%5Bid%5D=2</td><td></td></tr>
<tr><td>type</td><td>fields[title]</td><td>Black or White</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item has been updated.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Delete</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Delete</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>//input[@name='check[]' and @value='where%5Bid%5D=2']</td><td></td></tr>
@@ -204,10 +194,9 @@
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>1 item has been affected.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Truncate</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Truncate</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>all</td><td></td></tr>
@@ -216,10 +205,9 @@
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>No rows.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Export</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Export</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;dump=</td><td></td></tr>
<tr><td>click</td><td>output</td><td></td></tr>
@@ -231,10 +219,38 @@
<tr><td>verifyTextPresent</td><td>INSERT INTO [dbo].[interprets]</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>VIEW [dbo].[albums_interprets]</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Drop</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3" data-tags="">Generated columns</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&amp;create=</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>generated</td></tr>
<tr><td>type</td><td>name=fields[1][field]</td><td>normal</td></tr>
<tr><td>type</td><td>name=fields[1.1][field]</td><td>virtual</td></tr>
<tr><td>select</td><td>name=fields[1.1][generated]</td><td>label=VIRTUAL</td></tr>
<tr><td>type</td><td>name=fields[1.1][default]</td><td>normal + 100</td></tr>
<tr><td>type</td><td>name=fields[1.11][field]</td><td>stored</td></tr>
<tr><td>select</td><td>name=fields[1.11][generated]</td><td>label=PERSISTED</td></tr>
<tr><td>type</td><td>name=fields[1.11][default]</td><td>normal + 200</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>[normal]+(100)</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>[normal]+(200)</td><td></td></tr>
<tr><td>click</td><td>link=Alter indexes</td><td></td></tr>
<tr><td>select</td><td>name=indexes[1][columns][1]</td><td>label=virtual</td></tr>
<tr><td>select</td><td>name=indexes[1][columns][11]</td><td>label=stored</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
<tr><td>click</td><td>link=New item</td><td></td></tr>
<tr><td>verifyTextNotPresent</td><td>virtual</td><td></td></tr>
<tr><td>verifyTextNotPresent</td><td>stored</td><td></td></tr>
<tr><td>type</td><td>name=fields[normal]</td><td>20</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>120</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>220</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Drop</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo</td><td></td></tr>
<tr><td>click</td><td>id=check-all</td><td></td></tr>
@@ -242,24 +258,23 @@
<tr><td>click</td><td>name=drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>No tables.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">SQL command</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">SQL command</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;sql=SELECT+122%2B1</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Execute']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>123</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Logout</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Logout</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC</td><td></td></tr>
<tr><td>clickAndWait</td><td>logout</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Logout successful.</td><td></td></tr>
<tr><td>open</td><td>/coverage.php</td><td></td></tr>
</tbody></table>
</body>
</html>

View File

@@ -6,10 +6,9 @@
<title>Katalon MySQL</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Login</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Login</td></tr></thead>
<tbody>
<tr><td>open</td><td>/coverage.php?coverage=0</td><td></td></tr>
<tr><td>open</td><td>/adminer/</td><td></td></tr>
@@ -17,17 +16,16 @@
<tr><td>clickAndWait</td><td>css=#lang &gt; input[type="submit"]</td><td></td></tr>
<tr><td>type</td><td>id=username</td><td>ODBC</td></tr>
<tr><td>type</td><td>name=auth[password]</td><td>ODBC</td></tr>
<tr><td>clickAndWait</td><td>xpath=//input[@value='Login']</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Login']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Logged as</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=SQL command</td><td></td></tr>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;sql=DROP+DATABASE+IF+EXISTS+adminer_test</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Execute']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Query executed OK</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create database</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create database</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create database</td><td></td></tr>
@@ -36,10 +34,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Database has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create table</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
@@ -58,10 +55,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create index</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create index</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter indexes</td><td></td></tr>
@@ -74,10 +70,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Partitioning</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Partitioning</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter table</td><td></td></tr>
@@ -97,10 +92,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create table 2</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create table 2</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
@@ -120,10 +114,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Foreign key</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Foreign key</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;table=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Add foreign key</td><td></td></tr>
@@ -132,10 +125,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Foreign key has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Alter table</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Alter table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter table</td><td></td></tr>
@@ -149,10 +141,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create trigger</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create trigger</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;trigger=albums</td><td></td></tr>
<tr><td>select</td><td>Timing</td><td>label=AFTER</td></tr>
@@ -160,27 +151,29 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Trigger has been created.</td><td></td></tr></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Check constraints</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Check constraints</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;table=albums</td><td></td></tr>
<tr><td>click</td><td>link=Create check</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>albums_interpret_check</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="clause"]').value = 'interpret > 0'</td><td></td></tr>
<tr><td>click</td><td>xpath=//input[@value='Save']</td><td></td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=New item</td><td></td></tr>
<tr><td>type</td><td>fields[interpret]</td><td>0</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check constraint 'albums_interpret_check' is violated.</td><td></td></tr>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;check=albums&amp;name=albums_interpret_check</td><td></td></tr>
<tr><td>verifyTextPresent<td>(`interpret` > 0)</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop albums_interpret_check?</td><td></td></tr>
<tr><td>click</td><td>name=drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create view</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create view</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;view=</td><td></td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="select"]').value = 'SELECT albums.id, albums.title, interprets.name FROM albums LEFT JOIN interprets ON albums.interpret = interprets.id'</td><td></td></tr>
@@ -188,10 +181,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>View has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Insert</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Insert</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;edit=interprets</td><td></td></tr>
<tr><td>type</td><td>fields[name]</td><td>Michael Jackson</td></tr>
@@ -203,10 +195,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item 1 has been inserted.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Clone</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Clone</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>check[]</td><td></td></tr>
@@ -215,10 +206,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item 2 has been inserted.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Explain</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Explain</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Edit</td><td></td></tr>
@@ -226,29 +216,26 @@
<tr><td>click</td><td>link=Explain</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>possible_keys</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Reference</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Reference</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=1</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Michael Jackson</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Update</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Update</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;edit=albums&amp;where%5Bid%5D=2</td><td></td></tr>
<tr><td>type</td><td>fields[title]</td><td>Black or White</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item has been updated.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Delete</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Delete</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>//input[@name='check[]' and @value='where%5Bid%5D=2']</td><td></td></tr>
@@ -257,10 +244,9 @@
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>1 item has been affected.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Truncate</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Truncate</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>all</td><td></td></tr>
@@ -269,10 +255,9 @@
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>No rows.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Privileges</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Privileges</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;user=</td><td></td></tr>
<tr><td>type</td><td>user</td><td>adminer_test</td></tr>
@@ -298,18 +283,16 @@
<tr><td>click</td><td>drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>User has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Process list</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Process list</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;processlist=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>SHOW FULL PROCESSLIST</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Export</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Export</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;dump=</td><td></td></tr>
<tr><td>click</td><td>output</td><td></td></tr>
@@ -322,10 +305,9 @@
<tr><td>verifyTextPresent</td><td>INSERT INTO `interprets`</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>VIEW `albums_interprets`</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Events</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Events</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;event=</td><td></td></tr>
<tr><td>type</td><td>EVENT_NAME</td><td>no_albums</td></tr>
@@ -340,10 +322,9 @@
<tr><td>click</td><td>drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Event has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Procedures</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Procedures</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;procedure=</td><td></td></tr>
<tr><td>clickAndWait</td><td>add[0]</td><td></td></tr>
@@ -368,44 +349,71 @@
<tr><td>click</td><td>drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Routine has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Variables</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3" data-tags="">Generated columns</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;create=</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>generated</td></tr>
<tr><td>type</td><td>name=fields[1][field]</td><td>normal</td></tr>
<tr><td>type</td><td>name=fields[1.1][field]</td><td>virtual</td></tr>
<tr><td>select</td><td>name=fields[1.1][generated]</td><td>label=VIRTUAL</td></tr>
<tr><td>type</td><td>name=fields[1.1][default]</td><td>normal + 100</td></tr>
<tr><td>type</td><td>name=fields[1.11][field]</td><td>stored</td></tr>
<tr><td>select</td><td>name=fields[1.11][generated]</td><td>label=STORED</td></tr>
<tr><td>type</td><td>name=fields[1.11][default]</td><td>normal + 200</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>`normal` + 100</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>`normal` + 200</td><td></td></tr>
<tr><td>click</td><td>link=Alter indexes</td><td></td></tr>
<tr><td>select</td><td>name=indexes[1][columns][1]</td><td>label=virtual</td></tr>
<tr><td>select</td><td>name=indexes[1][columns][11]</td><td>label=stored</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
<tr><td>click</td><td>link=New item</td><td></td></tr>
<tr><td>verifyTextNotPresent</td><td>virtual</td><td></td></tr>
<tr><td>verifyTextNotPresent</td><td>stored</td><td></td></tr>
<tr><td>type</td><td>name=fields[normal]</td><td>20</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>120</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>220</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Variables</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;variables=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>basedir</td><td></td></tr>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;status=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Uptime</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">History</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">History</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;sql=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>DROP DATABASE IF EXISTS adminer_test</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Warnings</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Warnings</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>xpath=(//a[contains(text(),'=')])[1]</td><td></td></tr>
<tr><td>click</td><td>//th[@id='th[interpret]']/span/a[2]</td><td></td></tr>
<tr><td>type</td><td>name=where[0][val]</td><td>1.2.3</td></tr>
<tr><td>submit</td><td>id=form</td><td></td></tr>
<tr><td>click</td><td>link=Warnings</td><td></td></tr>
<tr><td>verifyText</td><td>//div[@id='warnings']/div/table/tbody/tr/td[3]</td><td>Truncated incorrect DOUBLE value: '1.2.3'</td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Editor</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Editor</td></tr></thead>
<tbody>
<tr><td>open</td><td>/editor/example.php</td><td></td></tr>
<tr><td>select</td><td>name=lang</td><td>label=English</td></tr>
<tr><td>clickAndWait</td><td>css=#lang &gt; input[type="submit"]</td><td></td></tr>
<tr><td>type</td><td>name=auth[username]</td><td>admin</td></tr>
<tr><td>click</td><td>xpath=//input[@value='Login']</td><td></td></tr>
<tr><td>click</td><td>//input[@value='Login']</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=New item</td><td></td></tr>
<tr><td>type</td><td>fields[name]</td><td>Michael Jackson</td></tr>
@@ -417,10 +425,9 @@
<tr><td>verifyTextPresent</td><td>Item 4 has been inserted.</td><td></td></tr>
<tr><td>clickAndWait</td><td>logout</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Logout</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Logout</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?username=ODBC</td><td></td></tr>
<tr><td>clickAndWait</td><td>logout</td><td></td></tr>
@@ -429,5 +436,6 @@
<tr><td>verifyTextPresent</td><td>Přihlásit se</td><td></td></tr>
<tr><td>open</td><td>/coverage.php</td><td></td></tr>
</tbody></table>
</body>
</html>

View File

@@ -6,10 +6,9 @@
<title>Katalon PostgreSQL</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Login</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Login</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/</td><td></td></tr>
<tr><td>select</td><td>name=lang</td><td>label=English</td></tr>
@@ -18,12 +17,11 @@
<tr><td>type</td><td>id=username</td><td>ODBC</td></tr>
<tr><td>type</td><td>name=auth[password]</td><td>ODBC</td></tr>
<tr><td>type</td><td>name=auth[db]</td><td>adminer_test</td></tr>
<tr><td>clickAndWait</td><td>xpath=//input[@value='Login']</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Login']</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create table</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
@@ -41,10 +39,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create index</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create index</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter indexes</td><td></td></tr>
@@ -57,10 +54,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create table 2</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create table 2</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
@@ -78,10 +74,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Foreign key</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Foreign key</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;table=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Add foreign key</td><td></td></tr>
@@ -90,10 +85,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Foreign key has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Alter table</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Alter table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter table</td><td></td></tr>
@@ -107,27 +101,29 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Check constraints</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Check constraints</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;table=albums</td><td></td></tr>
<tr><td>click</td><td>link=Create check</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>albums_interpret_check</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="clause"]').value = 'interpret > 0'</td><td></td></tr>
<tr><td>click</td><td>xpath=//input[@value='Save']</td><td></td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=New item</td><td></td></tr>
<tr><td>type</td><td>fields[interpret]</td><td>0</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>violates check constraint</td><td></td></tr>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;check=albums&amp;name=albums_interpret_check</td><td></td></tr>
<tr><td>verifyTextPresent<td>(interpret > 0)</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop albums_interpret_check?</td><td></td></tr>
<tr><td>click</td><td>name=drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Create view</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Create view</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;view=</td><td></td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="select"]').value = 'SELECT albums.id, albums.title, interprets.name FROM albums LEFT JOIN interprets ON albums.interpret = interprets.id'</td><td></td></tr>
@@ -135,10 +131,20 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>View has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Insert</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Materialized view</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;view=</td><td></td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="select"]').value = 'SELECT albums.id, albums.title, interprets.name FROM albums LEFT JOIN interprets ON albums.interpret = interprets.id'</td><td></td></tr>
<tr><td>type</td><td>name</td><td>materialized_view</td></tr>
<tr><td>click</td><td>materialized</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Materialized view</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Insert</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;edit=interprets</td><td></td></tr>
<tr><td>type</td><td>fields[name]</td><td>Michael Jackson</td></tr>
@@ -150,10 +156,9 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item has been inserted.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Clone</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Clone</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>check[]</td><td></td></tr>
@@ -162,10 +167,35 @@
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>1 item has been affected.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Explain</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3" data-tags="">Enum</td></tr></thead>
<tbody>
<tr><td>open</td><td>http://localhost:8080/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public</td><td></td></tr>
<tr><td>click</td><td>link=Create type</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>alive</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="as"]').value = "AS ENUM('alive', 'deceased')"</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>click</td><td>link=interprets</td><td></td></tr>
<tr><td>click</td><td>link=Alter table</td><td></td></tr>
<tr><td>click</td><td>name=add[3]</td><td></td></tr>
<tr><td>type</td><td>name=fields[4][field]</td><td>alive</td></tr>
<tr><td>select</td><td>name=fields[4][type]</td><td>label=alive</td></tr>
<tr><td>click</td><td>name=fields[4][null]</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>click</td><td>link=alive</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>'alive', 'deceased'</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop alive?</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Drop']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>cannot drop type</td><td></td></tr>
<tr><td>open</td><td>http://localhost:8080/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;edit=interprets&amp;where%5Bid%5D=1</td><td></td></tr>
<tr><td>click</td><td>//input[@value='deceased']</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>deceased</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Explain</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Edit</td><td></td></tr>
@@ -173,29 +203,26 @@
<tr><td>click</td><td>link=Explain</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Seq Scan</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Reference</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Reference</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=1</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Michael Jackson</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Update</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Update</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;edit=albums&amp;where%5Bid%5D=2</td><td></td></tr>
<tr><td>type</td><td>fields[title]</td><td>Black or White</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item has been updated.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Delete</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Delete</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>//input[@name='check[]' and @value='where%5Bid%5D=2']</td><td></td></tr>
@@ -204,10 +231,9 @@
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>1 item has been affected.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Truncate</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Truncate</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>all</td><td></td></tr>
@@ -216,18 +242,16 @@
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>No rows.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Process list</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Process list</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;processlist=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>pg_stat_activity</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Export</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Export</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;dump=</td><td></td></tr>
<tr><td>click</td><td>output</td><td></td></tr>
@@ -239,10 +263,9 @@
<tr><td>verifyTextPresent</td><td>INSERT INTO "interprets"</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>VIEW "albums_interprets"</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Procedures</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Procedures</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;procedure=</td><td></td></tr>
<tr><td>clickAndWait</td><td>add[0]</td><td></td></tr>
@@ -268,10 +291,31 @@
<tr><td>click</td><td>drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Routine has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Drop</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3" data-tags="">Generated columns</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&amp;create=</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>generated</td></tr>
<tr><td>type</td><td>name=fields[1][field]</td><td>normal</td></tr>
<tr><td>type</td><td>name=fields[1.1][field]</td><td>stored</td></tr>
<tr><td>select</td><td>name=fields[1.1][generated]</td><td>label=STORED</td></tr>
<tr><td>type</td><td>name=fields[1.1][default]</td><td>normal + 200</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>normal + 200</td><td></td></tr>
<tr><td>click</td><td>link=Alter indexes</td><td></td></tr>
<tr><td>select</td><td>name=indexes[1][columns][1]</td><td>label=stored</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
<tr><td>click</td><td>link=New item</td><td></td></tr>
<tr><td>verifyTextNotPresent</td><td>stored</td><td></td></tr>
<tr><td>type</td><td>name=fields[normal]</td><td>20</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>220</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Drop</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public</td><td></td></tr>
<tr><td>click</td><td>id=check-all</td><td></td></tr>
@@ -279,32 +323,30 @@
<tr><td>click</td><td>name=drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>No tables.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Variables</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Variables</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;variables=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>autovacuum</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">SQL command</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">SQL command</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;sql=SELECT+122%2B1</td><td></td></tr>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;sql=SELECT+122%2B1</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Execute']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>123</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Logout</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Logout</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC</td><td></td></tr>
<tr><td>clickAndWait</td><td>logout</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Logout successful.</td><td></td></tr>
<tr><td>open</td><td>/coverage.php</td><td></td></tr>
</tbody></table>
</body>
</html>

View File

@@ -1,36 +0,0 @@
<?php
include __DIR__ . "/../adminer/include/errors.inc.php";
include __DIR__ . "/../php_shrink.inc.php";
function check($code, $expected) {
$shrinked = str_replace("\n", " ", php_shrink("<?php\n$code"));
if ("<?php $expected" != $shrinked) {
$backtrace = reset(debug_backtrace());
echo "$backtrace[file]:$backtrace[line]:" . substr($shrinked, 6) . "\n";
}
}
check('$ab = 1; echo $ab;', '$a=1;echo$a;');
check('$ab = 1; $cd = 2;', '$a=1;$b=2;');
check('define("AB", 1);', 'define("AB",1);');
check('function f($ab, $cd = 1) { return $ab; }', 'function f($a,$b=1){return$a;}');
check('class C { var $ab = 1; }', 'class C{var$ab=1;}');
check('class C { public $ab = 1; }', 'class C{var$ab=1;}');
check('class C { protected $ab = 1; }', 'class C{protected$ab=1;}');
check('class C { private $ab = 1; }', 'class C{private$ab=1;}');
check('class C { private $ab = 1; }', 'class C{private$ab=1;}');
check('class C { private function f($ab) { return $ab; }}', 'class C{private function f($a){return$a;}}');
check('class C { public function f($ab) { return $ab; }}', 'class C{function f($a){return$a;}}');
check('class C { private static $ab; }', 'class C{private static$ab;}');
check('class C { const AB = 1; }', 'class C{const AB=1;}');
check('class C { private const AB = 1; }', 'class C{private const AB=1;}');
check('class C { public $ab; function f($cd) { return $cd . $this->ab; }}', 'class C{var$ab;function f($b){return$b.$this->ab;}}');
check('namespace NS { class C { public $ab = 1; } } new NS\C; $ab = 2;', 'namespace NS{class C{var$ab=1;}}new NS\C;$a=2;');
check('new \stdClass;', 'new \stdClass;');
check('if (true) { echo "a"; } else { echo "b"; }', 'if(true)echo"a";else echo"b";');
check('echo $_GET["a"];', 'echo$_GET["a"];');
check('$ab = 1; echo "$ab";', '$a=1;echo"$a";');
check('echo 1; echo 3;', 'echo 1,3;');
check('echo 1; ?>2<?php echo 3;', "echo 1,'2',3;");
check('/** preserve */ $a; /** ignore */ /* also ignore */ // ignore too', '/** preserve */$a;');
check('$a = 1; ?><?php ?><?php $a = 2;', '$a=1;$a=2;');

View File

@@ -6,16 +6,15 @@
<title>Katalon SQLite</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">SQLite</td></tr>
</thead>
<thead><tr><td rowspan="1" colspan="3">Login</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php</td><td></td></tr>
<tr><td>select</td><td>name=lang</td><td>label=English</td></tr>
<tr><td>clickAndWait</td><td>css=#lang &gt; input[type="submit"]</td><td></td></tr>
<tr><td>select</td><td>name=auth[driver]</td><td>label=SQLite</td></tr>
<tr><td>type</td><td>id=username</td><td>admin</td></tr>
<tr><td>type</td><td>id=username</td><td>ODBC</td></tr>
<tr><td>type</td><td>name=auth[password]</td><td>YOUR_PASSWORD_HERE</td></tr>
<tr><td>click</td><td>css=input[type="submit"]</td><td></td></tr>
<tr><td>click</td><td>link=Create database</td><td></td></tr>
@@ -25,39 +24,253 @@
<tr><td>type</td><td>name=name</td><td>adminer_test.sqlite</td></tr>
<tr><td>click</td><td>css=input[type="submit"]</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Database has been created.</td><td></td></tr>
<tr><td>click</td><td>link=Create table</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>interprets</td></tr>
<tr><td>click</td><td>css=label.block &gt; input[name="auto_increment_col"]</td><td></td></tr>
<tr><td>type</td><td>name=fields[1.1][field]</td><td>name</td></tr>
<tr><td>select</td><td>name=fields[1.1][type]</td><td>label=text</td></tr>
<tr><td>click</td><td>xpath=(//input[@value='Save'])[2]</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Create table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
<tr><td>type</td><td>name</td><td>interprets</td></tr>
<tr><td>type</td><td>fields[1][field]</td><td>id</td></tr>
<tr><td>select</td><td>fields[1][type]</td><td>label=integer</td></tr>
<tr><td>click</td><td>//input[@name='auto_increment_col' and @value='1']</td><td></td></tr>
<tr><td>type</td><td>fields[1.1][field]</td><td>name</td></tr>
<tr><td>select</td><td>fields[1.1][type]</td><td>label=text</td></tr>
<tr><td>type</td><td>fields[1.1][length]</td><td>50</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
<tr><td>click</td><td>link=New item</td><td></td></tr>
<tr><td>type</td><td>name=fields[name]</td><td>Michael Jackson</td></tr>
<tr><td>click</td><td>css=input[type="submit"]</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Create index</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter indexes</td><td></td></tr>
<tr><td>select</td><td>indexes[2][type]</td><td>label=PRIMARY</td></tr>
<tr><td>select</td><td>indexes[2][columns][1]</td><td>label=name</td></tr>
<tr><td>verifyValue</td><td>name=indexes[2][name]</td><td>interprets_name</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>has more than one primary key</td><td></td></tr>
<tr><td>select</td><td>indexes[2][type]</td><td>label=INDEX</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Create table 2</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Create table</td><td></td></tr>
<tr><td>type</td><td>name</td><td>albums</td></tr>
<tr><td>type</td><td>fields[1][field]</td><td>id</td></tr>
<tr><td>select</td><td>fields[1][type]</td><td>label=integer</td></tr>
<tr><td>click</td><td>//input[@name='auto_increment_col' and @value='1']</td><td></td></tr>
<tr><td>type</td><td>fields[1.1][field]</td><td>interpret</td></tr>
<tr><td>select</td><td>fields[1.1][type]</td><td>label=integer</td></tr>
<tr><td>type</td><td>fields[1.11][field]</td><td>title</td></tr>
<tr><td>select</td><td>fields[1.11][type]</td><td>label=text</td></tr>
<tr><td>type</td><td>fields[1.11][length]</td><td>50</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Foreign key</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;table=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Add foreign key</td><td></td></tr>
<tr><td>selectAndWait</td><td>table</td><td>label=interprets</td></tr>
<tr><td>select</td><td>source[0]</td><td>label=interpret</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Foreign key has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Alter table</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;table=interprets</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter table</td><td></td></tr>
<tr><td>click</td><td>add[2]</td><td></td></tr>
<tr><td>type</td><td>fields[2.1][field]</td><td>albums</td></tr>
<tr><td>select</td><td>fields[2.1][type]</td><td>label=integer</td></tr>
<tr><td>type</td><td>fields[2.1][length]</td><td></td></tr>
<tr><td>uncheck</td><td>name=defaults</td><td></td></tr>
<tr><td>clickAndWait</td><td>name=defaults</td><td></td></tr>
<tr><td>type</td><td>name=fields[2.1][default]</td><td>0</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Table has been altered.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Create trigger</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;trigger=albums</td><td></td></tr>
<tr><td>select</td><td>Timing</td><td>label=AFTER</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="Statement"]').value = 'BEGIN\nUPDATE interprets SET albums = albums + 1 WHERE id = NEW.interpret;\nEND'</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Trigger has been created.</td><td></td></tr></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Check constraints</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;table=albums</td><td></td></tr>
<tr><td>click</td><td>link=Create check</td><td></td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="clause"]').value = 'interpret > 0'</td><td></td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=New item</td><td></td></tr>
<tr><td>type</td><td>fields[interpret]</td><td>0</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>CHECK constraint failed</td><td></td></tr>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;check=albums&amp;name=interpret+%3E+0</td><td></td></tr>
<tr><td>verifyTextPresent<td>interpret > 0</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop interpret > 0?</td><td></td></tr>
<tr><td>click</td><td>name=drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been dropped.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Create view</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;view=</td><td></td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="select"]').value = 'SELECT albums.id, albums.title, interprets.name FROM albums LEFT JOIN interprets ON albums.interpret = interprets.id'</td><td></td></tr>
<tr><td>type</td><td>name</td><td>albums_interprets</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>View has been created.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Insert</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;edit=interprets</td><td></td></tr>
<tr><td>type</td><td>fields[name]</td><td>Michael Jackson</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item 1 has been inserted.</td><td></td></tr>
<tr><td>click</td><td>link=Create table</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>albums</td></tr>
<tr><td>click</td><td>css=label.block &gt; input[name="auto_increment_col"]</td><td></td></tr>
<tr><td>type</td><td>name=fields[1.1][field]</td><td>interpret</td></tr>
<tr><td>select</td><td>name=fields[1.1][on_delete]</td><td>label=CASCADE</td></tr>
<tr><td>type</td><td>name=fields[1.11][field]</td><td>title</td></tr>
<tr><td>select</td><td>name=fields[1.11][type]</td><td>label=text</td></tr>
<tr><td>click</td><td>xpath=(//input[@value='Save'])[2]</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>interprets(id)</td><td></td></tr>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;edit=albums</td><td></td></tr>
<tr><td>type</td><td>fields[interpret]</td><td>1</td></tr>
<tr><td>type</td><td>fields[title]</td><td>Dangerous</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item 1 has been inserted.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Clone</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>check[]</td><td></td></tr>
<tr><td>clickAndWait</td><td>clone</td><td></td></tr>
<tr><td>type</td><td>fields[title]</td><td>Black and White</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item 2 has been inserted.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Explain</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Edit</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Execute']</td><td></td></tr>
<tr><td>click</td><td>link=Explain</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>SCAN albums</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Reference</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;select=albums</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=1</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Michael Jackson</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Update</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;edit=albums&amp;where%5Bid%5D=2</td><td></td></tr>
<tr><td>type</td><td>fields[title]</td><td>Black or White</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Item has been updated.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Delete</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>//input[@name='check[]' and @value='where%5Bid%5D=2']</td><td></td></tr>
<tr><td>waitForChecked</td><td>//input[@name='check[]' and @value='where%5Bid%5D=2']</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Are you sure?</td><td></td></tr>
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>1 item has been affected.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Truncate</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;select=albums</td><td></td></tr>
<tr><td>click</td><td>all</td><td></td></tr>
<tr><td>waitForChecked</td><td>all</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Are you sure?</td><td></td></tr>
<tr><td>click</td><td>delete</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>No rows.</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Export</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;dump=</td><td></td></tr>
<tr><td>click</td><td>output</td><td></td></tr>
<tr><td>click</td><td>format</td><td></td></tr>
<tr><td>select</td><td>table_style</td><td>label=DROP+CREATE</td></tr>
<tr><td>select</td><td>data_style</td><td>label=INSERT</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Export']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>CREATE TABLE "interprets"</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>CREATE TRIGGER "albums_ai"</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>INSERT INTO "interprets"</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>VIEW "albums_interprets"</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3" data-tags="">Generated columns</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;create=</td><td></td></tr>
<tr><td>type</td><td>name=name</td><td>generated</td></tr>
<tr><td>type</td><td>name=fields[1][field]</td><td>normal</td></tr>
<tr><td>type</td><td>name=fields[1.1][field]</td><td>stored</td></tr>
<tr><td>select</td><td>name=fields[1.1][generated]</td><td>label=STORED</td></tr>
<tr><td>type</td><td>name=fields[1.1][default]</td><td>normal + 200</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>normal + 200</td><td></td></tr>
<tr><td>click</td><td>link=Alter indexes</td><td></td></tr>
<tr><td>select</td><td>name=indexes[1][columns][1]</td><td>label=stored</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Indexes have been altered.</td><td></td></tr>
<tr><td>click</td><td>link=New item</td><td></td></tr>
<tr><td>type</td><td>name=fields[interpret]</td><td>1</td></tr>
<tr><td>type</td><td>name=fields[title]</td><td>Dangerous</td></tr>
<tr><td>click</td><td>css=input[type="submit"]</td><td></td></tr>
<tr><td>click</td><td>link=1</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Select: interprets</td><td></td></tr>
<tr><td>click</td><td>link=adminer_test.sqlite</td><td></td></tr>
<tr><td>click</td><td>link=Alter database</td><td></td></tr>
<tr><td>verifyTextNotPresent</td><td>stored</td><td></td></tr>
<tr><td>type</td><td>name=fields[normal]</td><td>20</td></tr>
<tr><td>click</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>220</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3">Variables</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;variables=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>integrity_check</td><td></td></tr>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;status=</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>MAX_COLUMN</td><td></td></tr>
</tbody></table>
<table cellpadding="1" cellspacing="1" border="1">
<thead><tr><td rowspan="1" colspan="3" data-tags="">Drop</td></tr></thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php?sqlite=&amp;username=ODBC&amp;db=adminer_test.sqlite&amp;database=</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop adminer_test.sqlite?</td><td></td></tr>
<tr><td>click</td><td>name=drop</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Database has been dropped.</td><td></td></tr>
<tr><td>click</td><td>id=logout</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Thanks for using Adminer, consider donating.</td><td></td></tr>
</tbody></table>
</body>
</html>

View File

@@ -44,6 +44,9 @@ Detection of table collation
Oracle:
clob comparable with string
CockroachDB:
Link docs to https://www.cockroachlabs.com/docs/v24.3/create-table
SimpleDB:
Report invalid user or password
Report API calls instead of queries