1
0
mirror of https://github.com/vrana/adminer.git synced 2025-09-05 04:01:48 +02:00

Compare commits

...

132 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
Jakub Vrana
967647759e Release 5.0.5 2025-03-13 18:28:43 +01:00
Jakub Vrana
e4323ced55 Tests: Fix CockroachDB after 48308f3 2025-03-13 18:22:06 +01:00
Jakub Vrana
85c6af6f87 Compile: strip space after CSS comment 2025-03-13 18:00:54 +01:00
Jakub Vrana
9226804aa2 CSS: Move media selector to <link> 2025-03-13 17:55:42 +01:00
Jakub Vrana
041e7064ca php_shrink: Simplify test 2025-03-13 17:45:16 +01:00
Jakub Vrana
4c2a8b0050 Compile: Move ?><? removal to php_shrink 2025-03-13 17:43:20 +01:00
Jakub Vrana
9afbf1a465 Compile: dark.css 2025-03-13 17:33:19 +01:00
Jakub Vrana
352ef9c778 CSS: Don't use dark theme with adminer.css 2025-03-13 17:11:40 +01:00
Jakub Vrana
45107dc46e Don't highlight NULL as JSON 2025-03-13 16:55:17 +01:00
Jakub Vrana
21f3426adb Design: Update dark mode (by rmsoft) 2025-03-13 16:48:56 +01:00
Jakub Vrana
95dccfe9fb MongoDB: Rename file 2025-03-13 15:21:19 +01:00
Jakub Vrana
fe88f83c95 Elastic: Fix number of rows in group queries 2025-03-13 14:34:26 +01:00
Jakub Vrana
078957fe32 MongoDB: Move to plugin 2025-03-13 14:27:54 +01:00
Jakub Vrana
61f07867f9 Update readme 2025-03-13 14:09:45 +01:00
Jakub Vrana
0135dd5b81 Tests: Add tests for MS SQL 2025-03-13 14:07:31 +01:00
Jakub Vrana
773a2253d3 Export: Display unknown number of rows as ? 2025-03-13 13:29:10 +01:00
Jakub Vrana
272042a30e Fix skipOriginal after unconvertFunction 2025-03-13 13:13:06 +01:00
Jakub Vrana
48308f3357 CockroachDB: Recognize unique_rowid() as auto_increment 2025-03-13 13:09:05 +01:00
Jakub Vrana
c90033a962 Test PostgreSQL: SQL command 2025-03-13 13:03:24 +01:00
Jakub Vrana
8bd022f974 CockroachDB: Fix test 2025-03-13 13:02:53 +01:00
Jakub Vrana
b1550b052d MySQL: Simplify checking for MariaDB 2025-03-13 12:24:35 +01:00
Jakub Vrana
9862846a7c CockroachDB: Declare support 2025-03-13 12:15:37 +01:00
Jakub Vrana
f14e3e38f6 CockroachDB: Disable processlist 2025-03-13 12:12:44 +01:00
Jakub Vrana
95262c4215 CSS: Fix style 2025-03-13 12:08:01 +01:00
Jakub Vrana
dacfdc4608 Tests: Work with JUSH textarea 2025-03-13 12:07:49 +01:00
Jakub Vrana
7636c253fb CockroachDB: Display version 2025-03-13 11:51:03 +01:00
Jakub Vrana
44d26a9dd3 Tests: Add tests for CockroachDB 2025-03-13 11:08:42 +01:00
Jakub Vrana
b229e7b583 Tests: Add tests for MariaDB and PostgreSQL 2025-03-13 10:45:53 +01:00
Jakub Vrana
8e91417be1 MySQL: Display converting function for binary, bit or geometry fields 2025-03-13 07:50:20 +01:00
Peter Knut
db7202fcf0 MySQL: Fix saving string default value of json field 2025-03-13 07:19:27 +01:00
Jakub Vrana
260487fbc2 Designs: Update rmsoft (fix #911) 2025-03-13 07:10:23 +01:00
Jakub Vrana
3ae964c915 Designs: Fix price 2025-03-13 07:06:43 +01:00
Jakub Vrana
d56c8cbaae CSS: Simplify .odds 2025-03-13 07:03:42 +01:00
Jakub Vrana
d347f88c54 Design: Update rmsoft (fix #911) 2025-03-13 06:38:32 +01:00
Jakub Vrana
b9b4db0c8e Compile: Add more php_shrink tests 2025-03-13 06:10:58 +01:00
Jakub Vrana
818b9ad903 Compile: Strip public 2025-03-12 23:15:24 +01:00
Jakub Vrana
4a6436773f Compile: Add tests for php_shrink 2025-03-12 23:15:22 +01:00
Jakub Vrana
81594e4a2d Issues: Prefer MySQLi 2025-03-12 18:28:56 +01:00
Jakub Vrana
f0bdb0e6ca Designs: Update .odds 2025-03-12 17:50:24 +01:00
Jakub Vrana
b9e4806d3c CSS: lowercase color names 2025-03-12 17:43:58 +01:00
Jakub Vrana
7e708dae57 CSS: Add dark theme 2025-03-12 17:42:53 +01:00
Jakub Vrana
a0fe44ec18 CSS: Expand <code> in <pre> 2025-03-12 17:35:44 +01:00
Jakub Vrana
eb0f280776 CSS: Fix highlighting checked odd rows 2025-03-12 17:35:34 +01:00
Jakub Vrana
3b1189cd3c MySQL: Allow setting default values of json column 2025-03-12 14:25:19 +01:00
Jakub Vrana
434a8f7705 CSS: Disable odd on hover 2025-03-12 13:58:20 +01:00
Jakub Vrana
f9478c67d2 CSS: Merge rules 2025-03-12 12:57:59 +01:00
Jakub Vrana
f2ce6c0a71 Wrap long lines 2025-03-12 11:43:21 +01:00
Jakub Vrana
a50b3d6385 MS SQL: Fix editing rows with datetime column in primary key
Inspired by adminneo-org@b4afc08.
This fixes https://sourceforge.net/p/adminer/discussion/960418/thread/a547e79622/.
2025-03-12 09:28:22 +01:00
Jakub Vrana
e39deca4f1 Wrap Schema: in navigation to <span> (fix #907) 2025-03-12 09:26:04 +01:00
Jakub Vrana
ce69970f54 Update German translation (by @wintstar) 2025-03-12 09:09:09 +01:00
Jakub Vrana
51ac1312a1 MariaDB: Don't display NULL as default value 2025-03-12 08:51:25 +01:00
Jakub Vrana
4505544953 Code style: exclude removed extensions 2025-03-12 08:12:28 +01:00
Jakub Vrana
fa75213ff6 Coverage: Fix newlines 2025-03-12 06:15:47 +01:00
Jakub Vrana
63acb37ea6 Coverage: Display drivers 2025-03-12 06:09:18 +01:00
Jakub Vrana
3ad6c16f59 Coverage: Modernize HTML 2025-03-12 06:06:28 +01:00
Jakub Vrana
22d08b4a50 Add comment 2025-03-12 06:01:29 +01:00
Jakub Vrana
dd3cc4e683 Add plugin AdminerEditorViews (fix #905) 2025-03-12 05:22:57 +01:00
Jakub Vrana
5504a617d0 Compile: Support private static 2025-03-12 05:03:42 +01:00
Jakub Vrana
2fdebfda29 Ensure PHP 5.3 compatibility 2025-03-11 21:43:59 +01:00
Jakub Vrana
dc2e945aef MySQL: Convert binary default value to hex when editing 2025-03-11 20:25:52 +01:00
Jakub Vrana
43d86287c4 Fix focusing first field 2025-03-11 20:16:49 +01:00
Jakub Vrana
a94a727af7 PostgreSQL PDO: Escape bytea values (bug #218) 2025-03-11 19:42:10 +01:00
Jakub Vrana
c2d29a6937 MySQL: Display default values of binary columns 2025-03-11 19:25:42 +01:00
Jakub Vrana
c082136558 Rename variable 2025-03-11 18:40:34 +01:00
Jakub Vrana
7b1ea5fa2c AdminerDumpAlter: Use dumpFooter 2025-03-11 18:20:11 +01:00
Jakub Vrana
156839142e Fix plugin AdminerPrettyJsonColumn 2025-03-11 18:16:44 +01:00
Jakub Vrana
2ee4e3b2e1 Compile: Fix shortening in protected functions 2025-03-11 17:56:21 +01:00
Jakub Vrana
8b4c8b0156 Fix coverage 2025-03-11 14:37:08 +01:00
Jakub Vrana
9702878297 Develop 2025-03-11 14:00:37 +01:00
Jakub Vrana
4a54648995 Release 5.0.4 2025-03-11 13:52:53 +01:00
Jakub Vrana
2e5027a1aa Compile: Fix shortening in private methods 2025-03-11 13:50:36 +01:00
89 changed files with 3310 additions and 1718 deletions

View File

@@ -8,7 +8,7 @@ assignees: ''
---
**Adminer version:** please use latest published or Git
**Driver:** e.g. MySQL
**Database version:** e.g. 10.1.48-MariaDB
**Driver:** e.g. MySQLi
**Database version:** e.g. 10.2.12-MariaDB
Please provide reproducible steps including a SQL dump (with no personal information) if applicable.

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) {
@@ -83,17 +83,18 @@ if ($_POST && !process_fields($row["fields"]) && !$error) {
$partitioning = "";
if (support("partitioning")) {
if (isset($partition_by[$row["partition_by"]])) {
$params = array_filter($row, function ($key) {
return preg_match('~^partition~', $key);
}, ARRAY_FILTER_USE_KEY);
$params = array();
foreach ($row as $key => $val) {
if (preg_match('~^partition~', $key)) {
$params[$key] = $val;
}
}
foreach ($params["partition_names"] as $key => $name) {
if ($name == "") {
unset($params["partition_names"][$key]);
unset($params["partition_values"][$key]);
}
}
if ($params != get_partitions_info($TABLE)) {
$partitions = array();
if ($params["partition_by"] == 'RANGE' || $params["partition_by"] == 'LIST') {
@@ -102,7 +103,6 @@ if ($_POST && !process_fields($row["fields"]) && !$error) {
$partitions[] = "\n PARTITION " . idf_escape($name) . " VALUES " . ($params["partition_by"] == 'RANGE' ? "LESS THAN" : "IN") . ($value != "" ? " ($value)" : " MAXVALUE"); //! SQL injection
}
}
// $params["partition"] can be expression, not only column
$partitioning .= "\nPARTITION BY $params[partition_by]($params[partition])";
if ($partitions) {
@@ -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

@@ -509,7 +509,16 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table), $connection2) as $row
foreach ($comments as $key => $val) {
$comment = substr($val, 9); // 9 - strlen(" COMMENT ")
queries("EXEC sp_dropextendedproperty @name = N'MS_Description', @level0type = N'Schema', @level0name = " . q(get_schema()) . ", @level1type = N'Table', @level1name = " . q($name) . ", @level2type = N'Column', @level2name = " . q($key));
queries("EXEC sp_addextendedproperty @name = N'MS_Description', @value = " . $comment . ", @level0type = N'Schema', @level0name = " . q(get_schema()) . ", @level1type = N'Table', @level1name = " . q($name) . ", @level2type = N'Column', @level2name = " . q($key));
queries("EXEC sp_addextendedproperty
@name = N'MS_Description',
@value = $comment,
@level0type = N'Schema',
@level0name = " . q(get_schema()) . ",
@level1type = N'Table',
@level1name = " . q($name) . ",
@level2type = N'Column',
@level2name = " . q($key))
;
}
return true;
}

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
@@ -330,6 +330,13 @@ if (!defined('Adminer\DRIVER')) {
}
}
function unconvertFunction($field) {
return (preg_match("~binary~", $field["type"]) ? "<code class='jush-sql'>UNHEX</code>"
: ($field["type"] == "bit" ? doc_link(array('sql' => 'bit-value-literals.html'), "<code>b''</code>")
: (preg_match("~geometry|point|linestring|polygon~", $field["type"]) ? "<code class='jush-sql'>GeomFromText</code>"
: "")));
}
function insert($table, $set) {
return ($set ? parent::insert($table, $set) : queries("INSERT INTO " . table($table) . " ()\nVALUES ()"));
}
@@ -361,7 +368,7 @@ if (!defined('Adminer\DRIVER')) {
function slowQuery($query, $timeout) {
if (min_version('5.7.8', '10.1.2')) {
if (preg_match('~MariaDB~', $this->conn->server_info)) {
if ($this->conn->maria) {
return "SET STATEMENT max_statement_time=$timeout FOR $query";
} elseif (preg_match('~^(SELECT\b)(.+)~is', $query, $match)) {
return "$match[1] /*+ MAX_EXECUTION_TIME(" . ($timeout * 1000) . ") */ $match[2]";
@@ -386,7 +393,7 @@ if (!defined('Adminer\DRIVER')) {
}
function tableHelp($name, $is_view = false) {
$maria = preg_match('~MariaDB~', $this->conn->server_info);
$maria = $this->conn->maria;
if (information_schema(DB)) {
return strtolower("information-schema-" . ($maria ? "$name-table/" : str_replace("_", "-", $name) . "-table.html"));
}
@@ -428,10 +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;
@@ -587,11 +597,11 @@ if (!defined('Adminer\DRIVER')) {
/** Get information about fields
* @param string
* @return array [$name => ["field" => , "full_type" => , "type" => , "length" => , "unsigned" => , "default" => , "null" => , "auto_increment" => , "on_update" => , "collation" => , "privileges" => , "comment" => , "primary" => , "generated" => ]]
* @return array [$name => ["field" =>, "full_type" =>, "type" =>, "length" =>, "unsigned" =>, "default" =>, "null" =>, "auto_increment" =>, "on_update" =>, "collation" =>, "privileges" =>, "comment" =>, "primary" =>, "generated" =>]]
*/
function fields($table) {
global $connection;
$maria = preg_match('~MariaDB~', $connection->server_info);
$maria = $connection->maria;
$return = array();
foreach (get_rows("SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = " . q($table) . " ORDER BY ORDINAL_POSITION") as $row) {
$field = $row["COLUMN_NAME"];
@@ -600,27 +610,32 @@ if (!defined('Adminer\DRIVER')) {
$extra = $row["EXTRA"];
// https://mariadb.com/kb/en/library/show-columns/, https://github.com/vrana/adminer/pull/359#pullrequestreview-276677186
preg_match('~^(VIRTUAL|PERSISTENT|STORED)~', $extra, $generated);
preg_match('~^([^( ]+)(?:\((.+)\))?( unsigned)?( zerofill)?$~', $type, $match);
preg_match('~^([^( ]+)(?:\((.+)\))?( unsigned)?( zerofill)?$~', $type, $match_type);
$default = $row["COLUMN_DEFAULT"];
$is_text = preg_match('~text~', $match[1]);
if (!$maria && $is_text) {
// default value a'b of text column is stored as _utf8mb4\'a\\\'b\' in MySQL
$default = preg_replace("~^(_\w+)?('.*')$~", '\2', stripslashes($default));
}
if ($maria || $is_text) {
$default = preg_replace_callback("~^'(.*)'$~", function ($match) {
return stripslashes(str_replace("''", "'", $match[1]));
}, $default);
if ($default != "") {
$is_text = preg_match('~text|json~', $match_type[1]);
if (!$maria && $is_text) {
// default value a'b of text column is stored as _utf8mb4\'a\\\'b\' in MySQL
$default = preg_replace("~^(_\w+)?('.*')$~", '\2', stripslashes($default));
}
if ($maria || $is_text) {
$default = ($default == "NULL" ? null : preg_replace_callback("~^'(.*)'$~", function ($match) {
return stripslashes(str_replace("''", "'", $match[1]));
}, $default));
}
if (!$maria && preg_match('~binary~', $match_type[1]) && preg_match('~^0x(\w*)$~', $default, $match)) {
$default = pack("H*", $match[1]);
}
}
$return[$field] = array(
"field" => $field,
"full_type" => $type,
"type" => $match[1],
"length" => $match[2],
"unsigned" => ltrim($match[3] . $match[4]),
"type" => $match_type[1],
"length" => $match_type[2],
"unsigned" => ltrim($match_type[3] . $match_type[4]),
"default" => ($generated
? ($maria ? $generation : stripslashes($generation))
: ($default != "" || preg_match("~char|set~", $match[1]) ? $default : null)
: $default
),
"null" => ($row["IS_NULLABLE"] == "YES"),
"auto_increment" => ($extra == "auto_increment"),
@@ -662,7 +677,12 @@ if (!defined('Adminer\DRIVER')) {
$return = array();
$create_table = get_val("SHOW CREATE TABLE " . table($table), 1);
if ($create_table) {
preg_match_all("~CONSTRAINT ($pattern) FOREIGN KEY ?\\(((?:$pattern,? ?)+)\\) REFERENCES ($pattern)(?:\\.($pattern))? \\(((?:$pattern,? ?)+)\\)(?: ON DELETE ($driver->onActions))?(?: ON UPDATE ($driver->onActions))?~", $create_table, $matches, PREG_SET_ORDER);
preg_match_all(
"~CONSTRAINT ($pattern) FOREIGN KEY ?\\(((?:$pattern,? ?)+)\\) REFERENCES ($pattern)(?:\\.($pattern))? \\(((?:$pattern,? ?)+)\\)(?: ON DELETE ($driver->onActions))?(?: ON UPDATE ($driver->onActions))?~",
$create_table,
$matches,
PREG_SET_ORDER
);
foreach ($matches as $match) {
preg_match_all("~$pattern~", $match[2], $source);
preg_match_all("~$pattern~", $match[5], $target);
@@ -806,7 +826,7 @@ if (!defined('Adminer\DRIVER')) {
$default = $field[1][3];
if (preg_match('~ GENERATED~', $default)) {
// swap default and null
$field[1][3] = (preg_match('~MariaDB~', $connection->server_info) ? "" : $field[1][2]); // MariaDB doesn't support NULL on virtual columns
$field[1][3] = ($connection->maria ? "" : $field[1][2]); // MariaDB doesn't support NULL on virtual columns
$field[1][2] = $default;
}
$alter[] = ($table != "" ? ($field[0] != "" ? "CHANGE " . idf_escape($field[0]) : "ADD") : " ") . " " . implode($field[1]) . ($table != "" ? $field[2] : "");
@@ -982,7 +1002,9 @@ if (!defined('Adminer\DRIVER')) {
global $driver;
$aliases = array("bool", "boolean", "integer", "double precision", "real", "dec", "numeric", "fixed", "national char", "national varchar");
$space = "(?:\\s|/\\*[\s\S]*?\\*/|(?:#|-- )[^\n]*\n?|--\r?\n)";
$type_pattern = "((" . implode("|", array_merge(array_keys($driver->types()), $aliases)) . ")\\b(?:\\s*\\(((?:[^'\")]|$driver->enumLength)++)\\))?\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s,]+)['\"]?)?";
$enum = $driver->enumLength;
$type_pattern = "((" . implode("|", array_merge(array_keys($driver->types()), $aliases)) . ")\\b(?:\\s*\\(((?:[^'\")]|$enum)++)\\))?"
. "\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s,]+)['\"]?)?";
$pattern = "$space*(" . ($type == "FUNCTION" ? "" : $driver->inout) . ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern";
$create = get_val("SHOW CREATE $type " . idf_escape($name), 2);
preg_match("~\\(((?:$pattern\\s*,?)*)\\)\\s*" . ($type == "FUNCTION" ? "RETURNS\\s+$type_pattern\\s+" : "") . "(.*)~is", $create, $match);
@@ -992,7 +1014,7 @@ if (!defined('Adminer\DRIVER')) {
$fields[] = array(
"field" => str_replace("``", "`", $param[2]) . $param[3],
"type" => strtolower($param[5]),
"length" => preg_replace_callback("~$driver->enumLength~s", 'Adminer\normalize_enum', $param[6]),
"length" => preg_replace_callback("~$enum~s", 'Adminer\normalize_enum', $param[6]),
"unsigned" => strtolower(preg_replace('~\s+~', ' ', trim("$param[8] $param[7]"))),
"null" => 1,
"full_type" => $param[4],
@@ -1192,7 +1214,7 @@ if (!defined('Adminer\DRIVER')) {
}
/** Check whether a feature is supported
* @param string "check", "comment", "copy", "database", "descidx", "drop_col", "dump", "event", "indexes", "kill", "materializedview", "partitioning", "privileges", "procedure", "processlist", "routine", "scheme", "sequence", "status", "table", "trigger", "type", "variables", "view", "view_trigger"
* @param string "check|comment|copy|database|descidx|drop_col|dump|event|indexes|kill|materializedview|partitioning|privileges|procedure|processlist|routine|scheme|sequence|status|table|trigger|type|variables|view|view_trigger"
* @return bool
*/
function support($feature) {

View File

@@ -521,7 +521,16 @@ AND c_src.TABLE_NAME = " . q($table);
}
function process_list() {
return get_rows('SELECT sess.process AS "process", sess.username AS "user", sess.schemaname AS "schema", sess.status AS "status", sess.wait_class AS "wait_class", sess.seconds_in_wait AS "seconds_in_wait", sql.sql_text AS "sql_text", sess.machine AS "machine", sess.port AS "port"
return get_rows('SELECT
sess.process AS "process",
sess.username AS "user",
sess.schemaname AS "schema",
sess.status AS "status",
sess.wait_class AS "wait_class",
sess.seconds_in_wait AS "seconds_in_wait",
sql.sql_text AS "sql_text",
sess.machine AS "machine",
sess.port AS "port"
FROM v$session sess LEFT OUTER JOIN v$sql sql
ON sql.sql_id = sess.sql_id
WHERE sess.type = \'USER\'

View File

@@ -43,17 +43,16 @@ if (isset($_GET["pgsql"])) {
}
function quote($string) {
return pg_escape_literal($this->link, $string);
return (function_exists('pg_escape_literal')
? pg_escape_literal($this->link, $string) // available since PHP 5.4.4
: "'" . pg_escape_string($this->link, $string) . "'"
);
}
function value($val, $field) {
return ($field["type"] == "bytea" && $val !== null ? pg_unescape_bytea($val) : $val);
}
function quoteBinary($string) {
return "'" . pg_escape_bytea($this->link, $string) . "'";
}
function select_db($database) {
global $adminer;
if ($database == $adminer->database()) {
@@ -173,10 +172,6 @@ if (isset($_GET["pgsql"])) {
return ($adminer->database() == $database);
}
function quoteBinary($s) {
return q($s);
}
function query($query, $unbuffered = false) {
$return = parent::query($query, $unbuffered);
if ($this->timeout) {
@@ -283,7 +278,7 @@ if (isset($_GET["pgsql"])) {
}
function quoteBinary($s) {
return $this->conn->quoteBinary($s);
return "'\\x" . bin2hex($s) . "'"; // available since PostgreSQL 8.1
}
function warnings() {
@@ -326,11 +321,18 @@ 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)) {
$connection->query("SET application_name = 'Adminer'");
}
$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;
@@ -432,7 +434,14 @@ WHERE relkind IN ('r', 'm', 'v', 'f', 'p')
'timestamp with time zone' => 'timestamptz',
);
foreach (
get_rows("SELECT a.attname AS field, format_type(a.atttypid, a.atttypmod) AS full_type, pg_get_expr(d.adbin, d.adrelid) AS default, a.attnotnull::int, col_description(c.oid, a.attnum) AS comment" . (min_version(10) ? ", a.attidentity" . (min_version(12) ? ", a.attgenerated" : "") : "") . "
get_rows("SELECT
a.attname AS field,
format_type(a.atttypid, a.atttypmod) AS full_type,
pg_get_expr(d.adbin, d.adrelid) AS default,
a.attnotnull::int,
col_description(c.oid, a.attnum) AS comment" . (min_version(10) ? ",
a.attidentity" . (min_version(12) ? ",
a.attgenerated" : "") : "") . "
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_attribute a ON c.oid = a.attrelid
@@ -460,7 +469,8 @@ ORDER BY a.attnum") as $row
}
$row["generated"] = ($row["attgenerated"] == "s" ? "STORED" : "");
$row["null"] = !$row["attnotnull"];
$row["auto_increment"] = $row['attidentity'] || preg_match('~^nextval\(~i', $row["default"]);
$row["auto_increment"] = $row['attidentity'] || preg_match('~^nextval\(~i', $row["default"])
|| preg_match('~^unique_rowid\(~', $row["default"]); // CockroachDB
$row["privileges"] = array("insert" => 1, "select" => 1, "update" => 1, "where" => 1, "order" => 1);
if (preg_match('~(.+)::[^,)]+(.*)~', $row["default"], $match)) {
$row["default"] = ($match[1] == "NULL" ? null : idf_unescape($match[1]) . $match[2]);
@@ -478,7 +488,12 @@ ORDER BY a.attnum") as $row
$return = array();
$table_oid = $connection2->result("SELECT oid FROM pg_class WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = current_schema()) AND relname = " . q($table));
$columns = get_key_vals("SELECT attnum, attname FROM pg_attribute WHERE attrelid = $table_oid AND attnum > 0", $connection2);
foreach (get_rows("SELECT relname, indisunique::int, indisprimary::int, indkey, indoption, (indpred IS NOT NULL)::int as indispartial FROM pg_index i, pg_class ci WHERE i.indrelid = $table_oid AND ci.oid = i.indexrelid ORDER BY indisprimary DESC, indisunique DESC", $connection2) as $row) {
foreach (
get_rows("SELECT relname, indisunique::int, indisprimary::int, indkey, indoption, (indpred IS NOT NULL)::int as indispartial
FROM pg_index i, pg_class ci
WHERE i.indrelid = $table_oid AND ci.oid = i.indexrelid
ORDER BY indisprimary DESC, indisunique DESC", $connection2) as $row
) {
$relname = $row["relname"];
$return[$relname]["type"] = ($row["indispartial"] ? "INDEX" : ($row["indisprimary"] ? "PRIMARY" : ($row["indisunique"] ? "UNIQUE" : "INDEX")));
$return[$relname]["columns"] = array();
@@ -698,7 +713,12 @@ ORDER BY conkey, conname") as $row
$columns[] = $row["event_object_column"];
}
$return = array();
foreach (get_rows('SELECT trigger_name AS "Trigger", action_timing AS "Timing", event_manipulation AS "Event", \'FOR EACH \' || action_orientation AS "Type", action_statement AS "Statement" FROM information_schema.triggers ' . "$where ORDER BY event_manipulation DESC") as $row) {
foreach (
get_rows('SELECT trigger_name AS "Trigger", action_timing AS "Timing", event_manipulation AS "Event", \'FOR EACH \' || action_orientation AS "Type", action_statement AS "Statement"
FROM information_schema.triggers' . "
$where
ORDER BY event_manipulation DESC") as $row
) {
if ($columns && $row["Event"] == "UPDATE") {
$row["Event"] .= " OF";
}
@@ -938,7 +958,11 @@ AND typelem = 0"
}
function support($feature) {
return preg_match('~^(check|database|table|columns|sql|indexes|descidx|comment|view|' . (min_version(9.3) ? 'materializedview|' : '') . 'scheme|routine|processlist|sequence|trigger|type|variables|drop_col|kill|dump)$~', $feature);
global $connection;
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

@@ -78,7 +78,7 @@ if (isset($_GET["sqlite"])) {
);
}
function __desctruct() {
function __destruct() {
return $this->result->finalize();
}
}

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");
@@ -9,6 +17,9 @@ if ($_GET["file"] == "favicon.ico") {
} elseif ($_GET["file"] == "default.css") {
header("Content-Type: text/css; charset=utf-8");
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;../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" type="text/css" 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
@@ -289,13 +294,14 @@ class Adminer {
* @return string
*/
function selectVal($val, $link, $field, $original) {
$return = ($val === null ? "<i>NULL</i>" : (preg_match("~char|binary|boolean~", $field["type"]) && !preg_match("~var~", $field["type"]) ? "<code>$val</code>" : $val));
$return = ($val === null ? "<i>NULL</i>"
: (preg_match("~char|binary|boolean~", $field["type"]) && !preg_match("~var~", $field["type"]) ? "<code>$val</code>"
: (preg_match('~json~', $field["type"]) ? "<code class='jush-js'>$val</code>"
: $val)
));
if (preg_match('~blob|bytea|raw|file~', $field["type"]) && !is_utf8($val)) {
$return = "<i>" . lang('%d byte(s)', strlen($original)) . "</i>";
}
if (preg_match('~json~', $field["type"])) {
$return = "<code class='jush-js'>$return</code>";
}
return ($link ? "<a href='" . h($link) . "'" . (is_url($link) ? target_blank() : "") . ">$return</a>" : $return);
}
@@ -987,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";
}
}
}
@@ -1011,31 +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";
}
}
$server_info = $connection->server_info;
?>
bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '\1', $server_info) : ""); ?>'<?php echo (preg_match('~MariaDB~', $server_info) ? ", 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
@@ -1076,14 +1088,14 @@ bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '
<?php
hidden_fields_get();
$db_events = script("mixin(qsl('select'), {onmousedown: dbMouseDown, onchange: dbChange});");
echo "<span title='" . lang('Database') . "'>" . lang('DB') . "</span>: " . ($databases
echo "<span title='" . lang('Database') . "'>" . lang('DB') . ":</span> " . ($databases
? html_select("db", array("" => "") + $databases, DB) . $db_events
: "<input name='db' value='" . h(DB) . "' autocapitalize='off' size='19'>\n"
);
echo "<input type='submit' value='" . lang('Use') . "'" . ($databases ? " class='hidden'" : "") . ">\n";
if (support("scheme")) {
if ($missing != "db" && DB != "" && $connection->select_db(DB)) {
echo "<br>" . lang('Schema') . ": " . html_select("ns", array("" => "") + $adminer->schemas(), $_GET["ns"]) . $db_events;
echo "<br><span>" . lang('Schema') . ":</span> " . html_select("ns", array("" => "") + $adminer->schemas(), $_GET["ns"]) . $db_events;
if ($_GET["ns"] != "") {
set_schema($_GET["ns"]);
}

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"])));
}
@@ -62,7 +66,6 @@ if (function_exists("get_magic_quotes_runtime") && get_magic_quotes_runtime()) {
set_magic_quotes_runtime(false);
}
@set_time_limit(0); // @ - can be disabled
@ini_set("zend.ze1_compatibility_mode", false); // @ - deprecated
@ini_set("precision", 15); // @ - can be disabled, 15 - internal PHP precision
include "../adminer/include/lang.inc.php";
@@ -73,9 +76,9 @@ include "../adminer/drivers/sqlite.inc.php";
include "../adminer/drivers/pgsql.inc.php";
include "../adminer/drivers/oracle.inc.php";
include "../adminer/drivers/mssql.inc.php";
include "../adminer/drivers/mongo.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

@@ -8,7 +8,13 @@ if (isset($_GET["import"])) {
$_GET["sql"] = $_GET["import"];
}
if (!(DB != "" ? $connection->select_db(DB) : isset($_GET["sql"]) || isset($_GET["dump"]) || isset($_GET["database"]) || isset($_GET["processlist"]) || isset($_GET["privileges"]) || isset($_GET["user"]) || isset($_GET["variables"]) || $_GET["script"] == "connect" || $_GET["script"] == "kill")) {
if (
!(DB != ""
? $connection->select_db(DB)
: isset($_GET["sql"]) || isset($_GET["dump"]) || isset($_GET["database"]) || isset($_GET["processlist"]) || isset($_GET["privileges"]) || isset($_GET["user"]) || isset($_GET["variables"])
|| $_GET["script"] == "connect" || $_GET["script"] == "kill"
)
) {
if (DB != "" || $_GET["refresh"]) {
restart_session();
set_session("dbs", null);

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

@@ -28,19 +28,25 @@ function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") {
<meta name="robots" content="noindex">
<meta name="viewport" content="width=device-width">
<title><?php echo $title_page; ?></title>
<link rel="stylesheet" type="text/css" href="../adminer/static/default.css">
<?php echo script_src("../adminer/static/functions.js"); ?>
<?php 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 foreach ($adminer->css() as $css) { ?>
<link rel="stylesheet" type="text/css" href="<?php echo h($css); ?>">
<?php } ?>
<?php } ?>
<body class="<?php echo lang('ltr'); ?> nojs">
<link rel="stylesheet" href="../adminer/static/default.css">
<?php
$css = $adminer->css();
$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");
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));
@@ -58,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

@@ -66,6 +66,13 @@ abstract class SqlDriver {
function enumLength($field) {
}
/** Function used to convert the value inputted by user
* @param array
* @return string or null
*/
function unconvertFunction($field) {
}
/** Select data from table
* @param string
* @param array result of $adminer->selectColumnsProcess()[0]

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,19 +194,24 @@ 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 ($collations ? "<input list='collations' name='" . h($key) . "[collation]'" . (preg_match('~(char|text|enum|set)$~', $type) ? "" : " class='hidden'") . " value='" . h($field["collation"]) . "' placeholder='(" . lang('collation') . ")'>" : '');
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') . ")'>"
: ''
);
echo ($driver->unsigned ? "<select name='" . h($key) . "[unsigned]'" . (!$type || preg_match(number_type(), $type) ? "" : " class='hidden'") . '><option>' . optionlist($driver->unsigned, $field["unsigned"]) . '</select>' : '');
echo (isset($field['on_update']) ? "<select name='" . h($key) . "[on_update]'" . (preg_match('~timestamp|datetime~', $type) ? "" : " class='hidden'") . '>'
. optionlist(array("" => "(" . lang('ON UPDATE') . ")", "CURRENT_TIMESTAMP"), (preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"]) ? "CURRENT_TIMESTAMP" : $field["on_update"]))
. '</select>' : ''
);
echo ($foreign_keys ? "<select name='" . h($key) . "[on_delete]'" . (preg_match("~`~", $type) ? "" : " class='hidden'") . "><option value=''>(" . lang('ON DELETE') . ")" . optionlist(explode("|", $driver->onActions), $field["on_delete"]) . "</select> " : " "); // space for IE
echo ($foreign_keys
? "<select name='" . h($key) . "[on_delete]'" . (preg_match("~`~", $type) ? "" : " class='hidden'") . "><option value=''>(" . lang('ON DELETE') . ")" . optionlist(explode("|", $driver->onActions), $field["on_delete"]) . "</select> "
: " " // space for IE
);
}
/** Get partition info
@@ -307,8 +288,8 @@ function default_value($field) {
$generated = $field["generated"];
return ($default === null ? "" : (in_array($generated, $driver->generated)
? (JUSH == "mssql" ? " AS ($default)" . ($generated == "VIRTUAL" ? "" : " $generated") . "" : " GENERATED ALWAYS AS ($default) $generated")
: " DEFAULT " . (!preg_match('~^GENERATED ~i', $default) && (preg_match('~char|binary|text|enum|set~', $field["type"]) || preg_match('~^(?![a-z])~i', $default))
? (JUSH == "sql" && preg_match('~text~', $field["type"]) ? "(" . q($default) . ")" : q($default)) // MySQL requires () around default value of text column
: " DEFAULT " . (!preg_match('~^GENERATED ~i', $default) && (preg_match('~char|binary|text|json|enum|set~', $field["type"]) || preg_match('~^(?![a-z])~i', $default))
? (JUSH == "sql" && preg_match('~text|json~', $field["type"]) ? "(" . q($default) . ")" : q($default)) // MySQL requires () around default value of text column
: str_ireplace("current_timestamp()", "CURRENT_TIMESTAMP", (JUSH == "sqlite" ? "($default)" : $default))
)
));
@@ -343,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>";
@@ -624,7 +602,7 @@ function doc_link($paths, $text = "<sup>?</sup>") {
'mssql' => "https://learn.microsoft.com/en-us/sql/",
'oracle' => "https://www.oracle.com/pls/topic/lookup?ctx=db" . preg_replace('~^.* (\d+)\.(\d+)\.\d+\.\d+\.\d+.*~s', '\1\2', $server_info) . "&id=",
);
if (preg_match('~MariaDB~', $server_info)) {
if ($connection->maria) {
$urls['sql'] = "https://mariadb.com/kb/en/";
$paths['sql'] = (isset($paths['mariadb']) ? $paths['mariadb'] : str_replace(".html", "/", $paths['sql']));
}

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
@@ -459,14 +302,14 @@ function where($where, $fields = array()) {
foreach ((array) $where["where"] as $key => $val) {
$key = bracket_escape($key, 1); // 1 - back
$column = escape_key($key);
$field_type = $fields[$key]["type"];
$return[] = $column
. (JUSH == "sql" && $fields[$key]["type"] == "json" ? " = CAST(" . q($val) . " AS JSON)"
. (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" ? " LIKE " . q(preg_replace('~[_%[]~', '[\0]', $val)) // LIKE because of text
: " = " . unconvert_field($fields[$key], q($val))
)))
: (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)))))
; //! enum and set
if (JUSH == "sql" && preg_match('~char|text~', $fields[$key]["type"]) && preg_match("~[^ -@]~", $val)) { // not just [a-z] to catch non-ASCII characters
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";
}
}
@@ -536,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
*/
@@ -720,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
@@ -832,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
@@ -887,172 +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;
}
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
*/
@@ -1078,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
@@ -1166,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;
}
@@ -1186,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);
}
@@ -1196,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;
}
@@ -1315,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();
@@ -1388,123 +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;
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];
}
}
$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 ($field["auto_increment"] || $function == "now" || $function == "uuid") {
$first++;
}
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
@@ -74,9 +76,9 @@ function lang($idf, $number = null) {
: ($LANG == 'sl' ? ($number % 100 == 1 ? 0 : ($number % 100 == 2 ? 1 : ($number % 100 == 3 || $number % 100 == 4 ? 2 : 3))) // different forms for 1, 2, 3-4, other
: ($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
: ($LANG == 'bs' || $LANG == 'ru' || $LANG == 'sr' || $LANG == '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
: (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
$translation = $translation[$pos];
}
$args = func_get_args();

View File

@@ -1,4 +1,4 @@
<?php
namespace Adminer;
$VERSION = "5.0.3";
$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

@@ -302,4 +302,10 @@ $translations = array(
'Unknown error.' => 'Unbekannter Fehler.',
'Database does not support password.' => 'Die Datenbank unterstützt kein Passwort.',
'Disable %s or enable %s or %s extensions.' => 'Deaktivieren Sie %s oder aktivieren Sie die Erweiterungen %s oder %s.',
'Check has been dropped.' => 'Check wurde abgebrochen.',
'Check has been altered.' => 'Check wurde geändert.',
'Check has been created.' => 'Check wurde erstellt.',
'Alter check' => 'Check ändern',
'Create check' => 'Check erstellen',
'Checks' => 'Checks',
);

View File

@@ -74,7 +74,9 @@ foreach ($schema as $name => $table) {
$left1 = $left - $table_pos[$name][1];
$i = 0;
foreach ($ref[0] as $source) {
echo "\n<div class='references' title='" . h($target_name) . "' id='refs$left-" . ($i++) . "' style='left: $left1" . "em; top: " . $table["fields"][$source]["pos"] . "em; padding-top: .5em;'><div style='border-top: 1px solid Gray; width: " . (-$left1) . "em;'></div></div>";
echo "\n<div class='references' title='" . h($target_name) . "' id='refs$left-" . ($i++) . "' style='left: $left1" . "em; top: " . $table["fields"][$source]["pos"] . "em; padding-top: .5em;'>"
. "<div style='border-top: 1px solid gray; width: " . (-$left1) . "em;'></div></div>"
;
}
}
}
@@ -84,8 +86,9 @@ foreach ($schema as $name => $table) {
$left1 = $left - $table_pos[$name][1];
$i = 0;
foreach ($columns as $target) {
echo "\n<div class='references' title='" . h($target_name) . "' id='refd$left-" . ($i++) . "' style='left: $left1" . "em; top: " . $table["fields"][$target]["pos"] . "em; height: 1.25em; background: url(../adminer/static/arrow.gif) no-repeat right center;'>"
. "<div style='height: .5em; border-bottom: 1px solid Gray; width: " . (-$left1) . "em;'></div>"
echo "\n<div class='references' title='" . h($target_name) . "' id='refd$left-" . ($i++) . "'"
. " style='left: $left1" . "em; top: " . $table["fields"][$target]["pos"] . "em; height: 1.25em; background: url(../adminer/static/arrow.gif) no-repeat right center;'>"
. "<div style='height: .5em; border-bottom: 1px solid gray; width: " . (-$left1) . "em;'></div>"
. "</div>"
;
}
@@ -106,7 +109,7 @@ foreach ($schema as $name => $table) {
$min_pos = min($min_pos, $pos1, $pos2);
$max_pos = max($max_pos, $pos1, $pos2);
}
echo "<div class='references' id='refl$left' style='left: $left" . "em; top: $min_pos" . "em; padding: .5em 0;'><div style='border-right: 1px solid Gray; margin-top: 1px; height: " . ($max_pos - $min_pos) . "em;'></div></div>\n";
echo "<div class='references' id='refl$left' style='left: $left" . "em; top: $min_pos" . "em; padding: .5em 0;'><div style='border-right: 1px solid gray; margin-top: 1px; height: " . ($max_pos - $min_pos) . "em;'></div></div>\n";
}
}
}

View File

@@ -25,7 +25,7 @@ if ($_GET["script"] == "db") {
$sums[$key] += ($table_status["Engine"] != "InnoDB" || $key != "Data_free" ? $table_status[$key] : 0);
}
} elseif (array_key_exists($key, $table_status)) {
json_row("$key-$name");
json_row("$key-$name", "?");
}
}
}

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);
@@ -452,8 +452,8 @@ if (!$columns && support("table")) {
$id = h("val[$unique_idf][" . bracket_escape($key) . "]");
$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|lob~', $field["type"]);
echo "<td id='$id'";
$text = preg_match('~text|json|lob~', $field["type"]);
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];

46
adminer/static/dark.css Normal file
View File

@@ -0,0 +1,46 @@
/** @author Robert Mesaros, https://www.rmsoft.sk */
body { color: #829bb0; background: #002240; }
a { color: #517fa8; }
a:visited { color: #517fa8; }
a:link:hover, a:visited:hover { color: #9bc0e1; }
h1 { border-color: #5e94c1; color: #ffddbf; background: #154269; }
h2 { border-color: #a3bdd3; color: #000; background: #3c678d; }
td, th { border-color: #0e416d; }
th { background: #11385a; }
thead td, thead th { color: #a8b05f; background: #011d35; }
thead th a { color: #a8b05f; }
fieldset { border-color: #16548a; }
code { background: #11385a; }
tbody tr:hover td, tbody tr:hover th { background: #133553; }
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; }
.js .column { background: #011d35; }
.error { color: red; background: #efdada; border: 1px solid #e76f6f; }
.error b { background: #002240; }
.message { color: #0b860b; background: #efe; border: 1px solid #7fbd7f; }
.message table { color: #829bb0; background: #002240; }
.char { color: #a949a9; }
.date { color: #59c159; }
.enum { color: #d55c5c; }
.binary { color: #9bc0e1; }
.odds tbody tr:nth-child(2n) { background: #042541; }
.js .checkable .checked td, .js .checkable .checked th { background: #10395c; color: #67a4a5; }
.js .checkable .checked:hover td, .js .checkable .checked:hover th { background: #133553; }
.js .checkable .checked a { color: #67a4a5; }
.icon { background-color: #062642; }
.icon:hover { background-color: #d1394e; }
.footer { border-top-color: rgba(0, 34, 64, .7); border-image-source: linear-gradient(rgba(0, 34, 64, 0.2), #002240); }
.footer > div { background: #002240; }
#menu p, #logins, #tables { border-color: #326b9c; }
#logins a, #tables a, #tables span { background: #002240; }
#breadcrumb { background: #154269; }
#h1 { color: #ffddbf; }
#version { color: #d2b397; }
#schema .table { border-color: #093459; }
#help { border-color: #666; background: #c7e4fe; }
#schema div.table a { color: #3c7bb3; }
#menu .active { color: #398c8d; }
#edit-fields tbody tr:hover td, #edit-fields tbody tr:hover th { background: #3b6f9d; }

View File

@@ -1,4 +1,5 @@
/** @author Ondrej Valka, http://valka.info */
body { color: #000; background: #fff; font: 90%/1.25 Verdana, Arial, Helvetica, sans-serif; margin: 0; min-width: fit-content; }
a { color: blue; text-decoration: none; }
a:visited { color: navy; }
@@ -25,12 +26,12 @@ pre { margin: 1em 0 0; }
td pre { margin: 0; }
pre, textarea { font: 100%/1.25 monospace; }
pre.jush { background: #fff; }
pre code { display: block; }
input, textarea { box-sizing: border-box; }
input, select { vertical-align: middle; }
input[type="radio"] { vertical-align: text-bottom; }
input.default { box-shadow: 1px 1px 1px #777; }
input.required { box-shadow: 1px 1px 1px red; }
input.maxlength { box-shadow: 1px 1px 1px red; }
input.required, input.maxlength { box-shadow: 1px 1px 1px red; }
input.wayoff { left: -1000px; position: absolute; }
.block { display: block; }
.version { color: #777; font-size: 62%; }
@@ -47,12 +48,10 @@ input.wayoff { left: -1000px; position: absolute; }
.date { color: #7F007F; }
.enum { color: #007F7F; }
.binary { color: red; }
.odds tbody tr:nth-child(2n) td { background: #F5F5F5; }
.odds tbody tr:nth-child(2n) { background: #F5F5F5; }
.js .checkable .checked td, .js .checkable .checked th { background: #ddf; }
.time { color: silver; font-size: 70%; }
.function { text-align: right; }
.number { text-align: right; }
.datetime { text-align: right; }
.function, .number, .datetime { text-align: right; }
.type { width: 15ex; }
.options select, .options input { width: 20ex; }
.view { font-style: italic; }

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

@@ -568,7 +568,7 @@ function functionChange() {
* @this HTMLTableCellElement
*/
function skipOriginal(first) {
var fnSelect = this.previousSibling.firstChild;
var fnSelect = qs('select', this.previousSibling);
if (fnSelect.selectedIndex < first) {
fnSelect.selectedIndex = first;
}
@@ -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

@@ -45,7 +45,11 @@ if (!is_view($table_status)) {
foreach ($foreign_keys as $name => $foreign_key) {
echo "<tr title='" . h($name) . "'>";
echo "<th><i>" . implode("</i>, <i>", array_map('Adminer\h', $foreign_key["source"])) . "</i>";
echo "<td><a href='" . h($foreign_key["db"] != "" ? preg_replace('~db=[^&]*~', "db=" . urlencode($foreign_key["db"]), ME) : ($foreign_key["ns"] != "" ? preg_replace('~ns=[^&]*~', "ns=" . urlencode($foreign_key["ns"]), ME) : ME)) . "table=" . urlencode($foreign_key["table"]) . "'>"
$link = ($foreign_key["db"] != ""
? preg_replace('~db=[^&]*~', "db=" . urlencode($foreign_key["db"]), ME)
: ($foreign_key["ns"] != "" ? preg_replace('~ns=[^&]*~', "ns=" . urlencode($foreign_key["ns"]), ME) : ME)
);
echo "<td><a href='" . h($link . "table=" . urlencode($foreign_key["table"])) . "'>"
. ($foreign_key["db"] != "" && $foreign_key["db"] != DB ? "<b>" . h($foreign_key["db"]) . "</b>." : "")
. ($foreign_key["ns"] != "" && $foreign_key["ns"] != $_GET["ns"] ? "<b>" . h($foreign_key["ns"]) . "</b>." : "")
. h($foreign_key["table"])

View File

@@ -148,7 +148,10 @@ echo "<table class='odds'>\n";
echo "<thead><tr><th colspan='2'>" . lang('Privileges') . doc_link(array('sql' => "grant.html#priv_level"));
$i = 0;
foreach ($grants as $object => $grant) {
echo '<th>' . ($object != "*.*" ? "<input name='objects[$i]' value='" . h($object) . "' size='10' autocapitalize='off'>" : "<input type='hidden' name='objects[$i]' value='*.*' size='10'>*.*"); //! separate db, table, columns, PROCEDURE|FUNCTION, routine
echo '<th>' . ($object != "*.*"
? "<input name='objects[$i]' value='" . h($object) . "' size='10' autocapitalize='off'>"
: "<input type='hidden' name='objects[$i]' value='*.*' size='10'>*.*"
); //! separate db, table, columns, PROCEDURE|FUNCTION, routine
$i++;
}
echo "</thead>\n";

View File

@@ -1,9 +1,37 @@
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 SF-218)
CockroachDB: Display version
CockroachDB: Recognize unique_rowid() as auto_increment
MS SQL: Fix editing rows with datetime column in primary key
MongoDB: Move to plugin
CSS: Add dark theme
Adminer 5.0.4 (released 2025-03-11):
Compile: Fix shortening in private methods (regression from 5.0.3)
Adminer 5.0.3 (released 2025-03-11):
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)
@@ -13,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
@@ -45,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
@@ -67,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
@@ -155,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
@@ -187,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
@@ -209,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@
@@ -223,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
@@ -239,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
@@ -280,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
@@ -301,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):
@@ -329,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
@@ -355,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
@@ -402,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)
@@ -449,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
@@ -466,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
@@ -479,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
@@ -549,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
@@ -560,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):
@@ -573,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
@@ -598,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
@@ -687,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
@@ -703,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
@@ -733,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
@@ -748,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)
@@ -760,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
@@ -784,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
@@ -798,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
@@ -811,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
@@ -862,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)
@@ -891,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)
@@ -910,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
@@ -966,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):
@@ -974,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
@@ -1053,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

@@ -3,6 +3,7 @@
include __DIR__ . "/adminer/include/version.inc.php";
include __DIR__ . "/adminer/include/errors.inc.php";
include __DIR__ . "/externals/JsShrink/jsShrink.php";
include __DIR__ . "/externals/PhpShrink/phpShrink.php";
function add_apo_slashes($s) {
return addcslashes($s, "\\'");
@@ -36,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")),
@@ -88,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");
}
}
}
@@ -120,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];
}
@@ -212,129 +198,8 @@ if (!$translations) {
';
}
function short_identifier($number, $chars) {
$return = '';
while ($number >= 0) {
$return .= $chars[$number % strlen($chars)];
$number = floor($number / strlen($chars)) - 1;
}
return $return;
}
// based on http://latrine.dgx.cz/jak-zredukovat-php-skripty
function php_shrink($input) {
global $VERSION;
$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;
$token[1] = substr_replace($token[1], "* @version $VERSION\n", -2, 0);
}
if ($token[0] == T_VAR || $token[0] == T_PUBLIC || $token[0] == T_PROTECTED || $token[0] == T_PRIVATE) {
if ($token[0] == T_PUBLIC && $tokens[$i+2][1][0] == '$') {
$token[1] = 'var';
}
$shortening = false;
} elseif (!$shortening) {
if ($token[1] == ';') {
$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 minify_css($file) {
return lzw_compress(preg_replace('~\s*([:;{},])\s*~', '\1', preg_replace('~/\*.*\*/~sU', '', $file)));
return lzw_compress(preg_replace('~\s*([:;{},])\s*~', '\1', preg_replace('~/\*.*?\*/\s*~s', '', $file)));
}
function minify_js($file) {
@@ -359,14 +224,6 @@ function compile_file($match) {
return '"' . add_quo_slashes($file) . '"';
}
if (!function_exists("each")) {
function each(&$arr) {
$key = key($arr);
next($arr);
return $key === null ? false : array($key, $arr[$key]);
}
}
function min_version() {
return true;
}
@@ -385,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"]);
}
@@ -411,11 +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");
if ($driver) {
$_GET[$driver] = true; // to load the driver
$file = preg_replace('~\*/~', "* @version $VERSION\n*/", $file, 1);
if ($vendor) {
$_GET[$vendor] = true; // to load the driver
include_once __DIR__ . $driver_path;
foreach ($features as $key => $feature) {
if (!Adminer\support($feature)) {
@@ -431,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 ($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);
@@ -472,18 +334,19 @@ if ($_SESSION["lang"]) {
$file = str_replace("switch_lang();", "", $file);
$file = str_replace('<?php echo $LANG; ?>', $_SESSION["lang"], $file);
}
$file = str_replace('<?php echo script_src("static/editing.js"); ?>' . "\n", "", $file);
$file = preg_replace('~\s+echo script_src\("\.\./externals/jush/modules/jush-(textarea|txt|js|" \. JUSH \. ")\.js"\);~', '', $file);
$file = str_replace('<link rel="stylesheet" type="text/css" href="../externals/jush/jush.css">' . "\n", "", $file);
$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 = 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 = preg_replace("~<\\?php\\s*\\?>\n?|\\?>\n?<\\?php~", '', $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

@@ -1,13 +1,14 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="cs">
<!DOCTYPE html>
<html lang="cs">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Coverage</title>
</head>
<body>
<?php
include "./adminer/include/errors.inc.php";
function xhtml_open_tags($s) {
// returns array of opened tags in $s
$return = array();
@@ -22,19 +23,20 @@ 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.</p>\n";
echo "<p class='error'>Xdebug has to be enabled.\n";
} elseif ($_GET["coverage"] === "0") {
file_put_contents($coverage_filename, serialize(array()));
echo "<p class='message'>Coverage started.</p>\n";
} elseif (preg_match('~^(adminer|editor)/(include/)?[-_.a-z0-9]+$~i', $_GET["coverage"])) {
echo "<p class='message'>Coverage started.\n";
} elseif (preg_match('~^(adminer|editor)/(include/|drivers/)?[-_.a-z0-9]+$~i', $_GET["coverage"])) {
// highlight single file
$filename = $_GET["coverage"];
$coverage = (file_exists($coverage_filename) ? unserialize(file_get_contents($coverage_filename)) : array());
$file = explode("<br />", highlight_file($filename, true));
$file = explode("\n", substr(highlight_file($filename, true), 5, -6)); // unwrap <pre></pre>
$prev_color = null;
$s = "";
echo "<pre>";
for ($l=0; $l <= count($file); $l++) {
$line = $file[$l];
$color = "#C0FFC0"; // tested
@@ -58,31 +60,28 @@ if (!extension_loaded("xdebug")) {
foreach (array_reverse($open_tags) as $tag) {
echo "</" . preg_replace('~ .*~', '', $tag) . ">";
}
echo "</div>\n";
echo "</div>";
$s = ($open_tags ? "<" . implode("><", $open_tags) . ">" : "");
$prev_color = $color;
}
$s .= "$line<br />\n";
$s .= "$line\n";
}
echo "</pre>";
} else {
if (file_exists($coverage_filename)) {
// display list of files
$coverage = unserialize(file_get_contents($coverage_filename));
echo "<table border='1' cellspacing='0'>\n";
foreach (array_merge(glob("adminer/*.php"), glob("adminer/include/*.php"), glob("editor/*.php"), glob("editor/include/*.php")) as $filename) {
foreach (array_merge(glob("adminer/*.php"), glob("adminer/drivers/*.php"), glob("adminer/include/*.php"), glob("editor/*.php"), glob("editor/include/*.php")) as $filename) {
$cov = $coverage[realpath($filename)];
$ratio = 0;
if (is_array($cov)) {
$values = array_count_values($cov);
$ratio = round(100 - 100 * $values[-1] / (count($cov) - $values[-2]));
}
echo "<tr><td align='right' style='background-color: " . ($ratio < 50 ? "Red" : ($ratio < 75 ? "#FFEA20" : "#A7FC9D")) . ";'>$ratio%</td><td><a href='coverage.php?coverage=$filename'>$filename</a></td></tr>\n";
echo "<tr><td align='right' style='background-color: " . ($ratio < 50 ? "Red" : ($ratio < 75 ? "#FFEA20" : "#A7FC9D")) . ";'>$ratio%<td><a href='coverage.php?coverage=$filename'>$filename</a>\n";
}
echo "</table>\n";
}
echo "<p><a href='coverage.php?coverage=0'>Start new coverage</a></p>\n";
echo "<p><a href='coverage.php?coverage=0'>Start new coverage</a>\n";
}
?>
</body>
</html>

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) td,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

@@ -112,7 +112,7 @@ border-bottom: 1px #BBB solid;
thead tr:hover td, thead tr:hover th {
background-color: #DDD !important;
}
tr:nth-child(2n) td, tr:nth-child(2n) th, .odd td, .odd th, tr.odd {
tr:nth-child(2n) td, tr:nth-child(2n) th {
background-color: #F1F1F1;
}
tr:hover td, tr:hover th {

View File

@@ -175,8 +175,7 @@
background: var(--color-darkPurple);
}
.odds tbody tr:nth-child(2n) th,
.odds tbody tr:nth-child(2n) td {
.odds tbody tr:nth-child(2n) {
background: var(--color-darkDraculaVSCode);
}

View File

@@ -133,7 +133,7 @@ th {
background:white;
}
.odds tbody tr:nth-child(2n) td {
.odds tbody tr:nth-child(2n) {
background:#fcfaf5;
}

View File

@@ -72,7 +72,7 @@ tr:first-child th {padding-right: 30px;}
td:first-child, th:first-child {border-left-width: 0;}
thead td, thead th {background-color: #DFDFDF; border: none; border-bottom: 1px #BBB solid;}
thead tr:hover td, thead tr:hover th {background-color: #DDD !important;}
tr:nth-child(2n) td, tr:nth-child(2n) th, .odds tbody tr:nth-child(2n) td, .odds tbody tr:nth-child(2n) th, .odds tbody tr:nth-child(2n) {background-color: #F1F1F1;}
tr:nth-child(2n) td, tr:nth-child(2n) th, .odds tbody tr:nth-child(2n), .odds tbody tr:nth-child(2n):not(.checked, :hover) {background-color: #F1F1F1;}
tr:hover td, tr:hover th {background-color: #BCD;}
fieldset {display: inline; vertical-align: top; padding: 2px 12px; margin: 25px 12px 12px 0; border: none; background-color: #F1F1F1; border: 1px solid #E3E3E3; position: relative;}
fieldset, x:-moz-any-link {padding-top: 4px;}

View File

@@ -378,7 +378,7 @@ thead td abbr, thead td sup, thead th acronym, thead th sup {
color: #cdf
}
.odds tbody tr:nth-child(2n) td {
.odds tbody tr:nth-child(2n) {
background: #fcfaf5
}

View File

@@ -153,7 +153,7 @@ th, td {
vertical-align: top;
}
.odds tbody tr:nth-child(2n) th, .odds tbody tr:nth-child(2n) td {
.odds tbody tr:nth-child(2n) {
background: #FCFAF5;
}

View File

@@ -132,7 +132,7 @@ th {
background:white;
}
.odds tbody tr:nth-child(2n) td {
.odds tbody tr:nth-child(2n) {
background:#fcfaf5;
}

View File

@@ -187,7 +187,7 @@ td.nowrap {
.binary {
color: red;
}
.odds tbody tr:nth-child(2n) td {
.odds tbody tr:nth-child(2n) {
background: transparent;
}
.js .checkable .checked td,

View File

@@ -169,7 +169,7 @@ th {
background:white;
}
.odds tbody tr:nth-child(2n) td {
.odds tbody tr:nth-child(2n) {
background:#fcfaf5;
}
@@ -181,7 +181,7 @@ th {
background: #f2f2f2;
}
#content tbody tr.checked td, .odds tbody tr:nth-child(2n).checked td {
#content tbody tr.checked td {
background:#fbe2e2;
color:red;
}

View File

@@ -65,7 +65,7 @@ thead td, thead th {
border-bottom: 1px #DDD solid; }
.nowrap tr:nth-child(2n) td, .nowrap tr:nth-child(2n) th {
background-color: #DEF; }
.odds tbody tr:nth-child(2n) td, .odds tbody tr:nth-child(2n) th {
.odds tbody tr:nth-child(2n) {
background-color: #DEF; } /* IEx */
tr.selected td, tr.selected th {
background-color: #ABC !important; }

View File

@@ -136,8 +136,7 @@ table.checkable tbody tr:hover th {
background: #bfb008;
}
.odds tbody tr:nth-child(2n) th,
.odds tbody tr:nth-child(2n) td {
.odds tbody tr:nth-child(2n) {
background: #f5f5f5;
}

View File

@@ -58,7 +58,7 @@ table{-moz-border-bottom-colors:none;-moz-border-left-colors:none;-moz-border-ri
td,th{-moz-border-bottom-colors:none;-moz-border-left-colors:none;-moz-border-right-colors:none;-moz-border-top-colors:none;border-color:-moz-use-text-color #999 #999 -moz-use-text-color;border-image:none;border-style:none solid solid none;border-width:0 1px 1px 0;padding:.2em .3em}
thead td,thead th{background:#eee;background:-moz-linear-gradient(top,#eee 0,#ccc 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#eee),color-stop(100%,#ccc));background:-webkit-linear-gradient(top,#eee 0,#ccc 100%);background:-o-linear-gradient(top,#eee 0,#ccc 100%);background:-ms-linear-gradient(top,#eee 0,#ccc 100%);background:linear-gradient(to bottom,#eee 0,#ccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee',endColorstr='#cccccc',GradientType=0)}
td{background-color:#f4f8ff}
.odds tbody tr:nth-child(2n) td{background-color:#fff}
.odds tbody tr:nth-child(2n){background-color:#fff}
tbody tr:hover td,tbody tr:hover th{background-color:#FFE}
p.tabs{margin:0 20px 0 0}
.jush-sql{background:0}
@@ -70,6 +70,7 @@ a:hover{color:#28c}
#logout:hover,#logins a:hover,#tables a:hover,#breadcrumb a:hover,.logout a:hover,.tabs a:hover{color:#fff;text-decoration:none;background:#93c9ff;background:-moz-linear-gradient(top,#93c9ff 0,#79b8f7 44%,#57a2ed 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#93c9ff),color-stop(44%,#79b8f7),color-stop(100%,#57a2ed));background:-webkit-linear-gradient(top,#93c9ff 0,#79b8f7 44%,#57a2ed 100%);background:-o-linear-gradient(top,#93c9ff 0,#79b8f7 44%,#57a2ed 100%);background:-ms-linear-gradient(top,#93c9ff 0,#79b8f7 44%,#57a2ed 100%);background:linear-gradient(to bottom,#93c9ff 0,#79b8f7 44%,#57a2ed 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#93c9ff',endColorstr='#57a2ed',GradientType=0)}
#breadcrumb a,#breadcrumb a:link{border:1px solid #246;padding:2px 6px;margin:1px auto;line-height:1.6em}
#logins a,#tables a{background:none repeat scroll 0 0 #fff;padding:2px 6px;margin:1px 0;font-size:.8em}
#lang{top:-4.5em;}
a[title='Show structure'],#tables a[title='Show structure']{border:0;background:0;color:#369}
.jush a{border:0;background:0;margin:0;padding:0}
a.active,a.active:link,a.active:hover{text-decoration:underline}

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

@@ -2,8 +2,8 @@
* @package Adminer.css - Theme CSS for Adminer --- [theme light] gray - orange B (with icons)
*
*//*!
* @version 4.17.1.2
* @date Thu, 27 Feb 2025 09:28:32 +0100
* @version 5.0.4.1
* @date Wed, 12 Mar 2025 21:35:32 +0100
* @author Robert Mesaros
* @copyright Copyright 2025 Robert Mesaros, rmSOFT, Slovakia
* @web https://www.rmsoft.sk
@@ -35,10 +35,6 @@
* Modified icons by Robert Mesaros
*
*/
#menu{padding:0 0 30px 0}
.ltr .logout{right:0;left:auto;margin-top:.5em}
.rtl .logout{left:0;right:auto;margin-top:.5em}
.rtl table.layout tbody{direction:ltr}
html{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}
*,*:before,*:after{box-sizing:inherit}
body{color:#000;background:#f0f0f0;font-family:Verdana,Arial,Helvetica,sans-serif;font-weight:normal;cursor:default;margin:0}
@@ -49,6 +45,9 @@ img{width:100%;max-width:100%}
#menu #h1{margin-left:10px}
#menu h1{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAdCAYAAAC9pNwMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozNDA3NDEwQ0Y0MkQxMUVGODA4RUNENTRFQzJENUU4RCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozNDA3NDEwQkY0MkQxMUVGODA4RUNENTRFQzJENUU4RCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRTREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Ph59M4AAAAPFSURBVHja7JZrSFNRHMDvvVvq1mNlucBK0g/lh+Us6oPrU0ERRFgRUqYUVEb2qTJ0vko0ZbMHiBT0sizSXEUfJGzN1CjBQLPCR/RwSYKp23RO3e527/r/57mxxpblhCD8w59z7t2553f+zx36Ulk5FYxkZpyiijVahUgkqnc62cu5arUGXrMl2tIkhmGuu91uGp4HXre0qB490A3C3IXfMVSQojl/QQYAHUzlNtvYPBhl2Xn5672gqBFxSmXF0WPpCTCfg+/EwUDBwkixeM4TmqZjzSbTFU1J8W00RiaTtUxMTJSfzctFd4Yq49eGJ6ekNETHxGyG50jQkWDAcoA+BqjSbDaXA/QqvBtFBWg6QGuJtSaapr7jB7AWrV0C6pguWAZurIeNFCaTqUxbUnwd3lkRAjoO0JswStApEGs1jJs4jusw9vTcEcI7LTBA3wA02mI2X/WFgvIIxCQC6EmIdQ7P898qb1Xs7O7qGiVrWWaa4C5PZopEy6RSKQfTYS8oRUYO1i3Hh4e6mlSA2sjhLHgwMdkoA04lI1noV8BVn/Nzsu/iFHTP2cIiHSTR9tNZaqYgP28/iecv4nA4ajmXi7NYLKPkcFbiDYomdcxNVVoul6s9JytzC/mYWxEVtfDQkbQKiUSyw26368/k5iTBexvZSxA0bD4Zx0An0E4B3Nfz5cu+zs4OJ+tgQwOBlfHxcSujo7MHBwfTLpZq69Cdq2NjFyWnpFaGhYVtA3hdU2PD4ecGQ78AhxjnQi6o29va1lVX3TNibAUwniSyq7PT+qKxcQjmduEHX0lQqSIgUZaOj4+FwyM2ipEP3d1msHRvQdG5GoQnqDYWAviEYDmErw/G1t7e3hAYQwiY+tm5Pn36aCdusATS+QsWDOBa8ArWInqGga6FltnQzcPDlrKvRmMTKSMRroXQ3AXd3fzq5ZCvQZ7kOnb8ONQXbYd+6/pNmBd70pXnfHPBAy8pKsojUNYruzmSEwzp0e5fwNCBFIFc7CXMZHbzIn9JT9wrJA/nVVasv8084PvVVVvftLbavIPvK6kHDqoUa9Zc+03J8V6WTike8FzpXJ4UtzUQOEIux98oCAdHzYCIJzsQw5M6s0LC+D01NIPxmQQz1D+SWfAs+D8FO1mn6w9uHUJ90zPSQOAvcdWOxERD4q5dSwjA/0KxuNmg1294/+7tGLlFuIOy+NbNG0b4s3YSSwIqyzr4Z/qnlv7+/iE/N42/FjokJBQ3lmI7JteUQK5E0Ajp6fZgLUaw0LNDp7juuomL2WCtRfkhwACjULOQ0RiwkAAAAABJRU5ErkJggg==");background-repeat:no-repeat}
#menu h1:hover{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAdCAYAAAC9pNwMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQUNCOTdFQkY0MkQxMUVGOUM0OUMyQTRDNjAyNzhENiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQUNCOTdFQUY0MkQxMUVGOUM0OUMyQTRDNjAyNzhENiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRTREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pq1mg9cAAAQtSURBVHja7JZdTFxFFIDP3J9dCgqUQimQIlBSWNoCNfVBYmo0jX9Jg014aYrWFzWGRl9MTHzpiy8k2kbrm9qUWtMaY9S2RqV9ADQm9o/+pHsvhW5Lw8/iLu6PC9yfvTOeWWbbC9ktlPWRk5ydvWfmzjfnzJkzlxz+7HNYSpIeD1QEAtB2+kew8vKgwdXn9Wsw1uR7tQTg+zhjfRs0fTeazWCT71ARwLt8jANgn0nMNO+9d+82nw6VSZCj3PE1VhcDnJIBpDnG8tC0TmvYvC8N5YJ9yq6C/L4/6je9jo8eVJITOMjY9lJCdBUdn6D0Sq0+9B6alTpZ7okwNrjGrzWjPnkwHO4oJKR8h8fzJfaXcLiUA3TLWkJ+x+WvQeglhL6N5jhqZIqxbyo1vQP/z6GOW5QN8nfI/KtrOVhZLogwllIuE4xVo6eXEJo3TumFOn2oS0D/Rv23WtPfxPYxVCvU5DuL41pMAOOWbf+ENu4sWR4YgUlVBUdRQHIcKJPlEQyvGqT02mLofC6BhRrFBPuhEOAZG20HJoOvHItEJtEeQ7WXFWrFtmGq+gm4+NLL6DUF23Ei3O4hpLRKVXkY/nFBRSKDjUlVxR8+Coc7BTSEGuZZr8w7xN6nlBZhS7LBqWHc3n/kyAkxaV2osWG4RJKqrtRvOluu6S0PtvCBxCg9iZtsBSwrJBYXEdFgKTAhpFuW5aW8v4p6RoTV7Bwb23F848aLxYRUhn2NN0o13Sf6kukX6vWhT7E5zoMm+mwOTTGxgIzfCQT2+v03bcu0vNmoLa2tzTW1tR+GpsNvHeru/pVP0FlcXHG4YsMFflSweEwdjUaf/2AyeEtEhWFincMM2/XzzOxzHaOjf6HNSIP5Sio1vz8+0NcXdncslqfb2sokSSqfTSRKRMbGTkSjE6hb0GM/h+8rKvoOwTtFAiUtxkYNQqI3TYNHkztlusEwMjJsiDMXzQZ+vLCQZy1gVFQxiWQ+u9P29g/EMMxNdxsbfhm2rH4+FHWWg6s0/QC2B0W1WjBvCvxOV9fXGHUD9zn5kD1el0oy6tzPhdM1tQD9A/ydWI0+9KKA8uShYogtkkpKJ9UCsKKoW7N56pIU0HGonDaMtG4H6OkBkVBxETUmgOljNZfxiPKfb0+dfGHw8uXE4lW55bX9b7Rt3bbtC/eR4wXFJY7rHC9dG/hPQX4BD820WHVGcNn69fHUTSPL9ydXDWPFF0wKLMkSB89wcPfHn9BMA03TnF0MxgKwYnDO9/EqeBW8Cl4Ati07ufTXD0ufb/J/gBW8Ejfvbm8/375nT6kAZB6oKH+e7+196sb1azPuC33FHh87+tVd/AKxhSdZ1bJMeq73t0gwGOT3duJR6nLGr1aPx8snzuflWFxr2ULpiAt++mEfDI8CTtdsb7p2Z9tmEWIrV2+5/CfAAOVxxSK4gGWJAAAAAElFTkSuQmCC")}
.rtl table.layout tbody td{display:flex}
.rtl table.layout~table thead th:first-child,.rtl table.layout~table tbody td:first-child{text-align:right !important}
.rtl table.layout~table thead th:last-child,.rtl table.layout~table tbody td:last-child{text-align:left !important}
h1{padding:.6em .4em;background:#c60;border:1px solid #894501;text-align:left}
#h1{color:#fff}
.version{color:#ddd;margin-left:8px}
@@ -99,7 +98,7 @@ code{background:#f0d6d6;padding:.2em .5em}
table code{font-size:130%;background:#f5e8ce;padding:.1em .3em}
code.jush-sql{background:#f0e8d6}
.rtl p code.jush-sql{background-position:right;clear:right;float:right}
pre.sqlarea{background:#e0e0e0;padding:5px}
pre{background:#e0e0e0 !important;padding:5px}
textarea{font-size:120%}
.ltr p.count{font-size:90%;margin:.8em 20px 8px 0}
.rtl p.count{font-size:90%;margin:.8em 0 8px 20px}
@@ -119,12 +118,12 @@ table{border-spacing:0}
table,td,th{border:0;border-collapse:separate}
.ltr table{margin:1.9em 0 0 0}
.rtl table{margin:1.9em 0 0 0}
.rtl table tbody td,.rtl table tbody th{text-align:right}
.rtl table tbody td,.rtl table tbody th{text-align:right !important}
.ltr table thead td:first-child,.ltr table thead th:first-child{border-left:1px solid #999}
.rtl table thead td:first-child,.rtl table thead th:first-child{border-right:1px solid #999}
table thead td,table thead th{height:1.6em;border-top:1px solid #999;border-bottom:1px solid #999}
.ltr table thead td,.ltr table thead th{border-right:1px solid #999}
.rtl table thead td,.rtl table thead th{border-left:1px solid #999;text-align:right !important}
.rtl table thead td,.rtl table thead th{border-left:1px solid #999}
table tbody tr:first-child td,table tbody tr:first-child th{border-top:1px solid #999}
.ltr table tbody td:first-child,.ltr table tbody th:first-child{border-left:1px solid #999}
.rtl table tbody td:first-child,.rtl table tbody th:first-child{border-right:1px solid #999}
@@ -421,9 +420,12 @@ input[type=radio]{margin-bottom:5px}
.rtl input[type=checkbox],.rtl input[type=radio],.rtl input[type=range],.rtl progress{margin-left:5px}
.ltr input[type=submit]{margin-right:10px}
.rtl input[type=submit]{margin-left:10px}
.ltr table.layout label,.ltr label.jsonly{margin-left:8px}
.rtl table.layout label,.rtl label.jsonly{margin-right:8px}
input,button,select,.sqlarea{border-radius:3px}
.sqlarea{background:#e0e0e0;font-size:105%}
fieldset a{line-height:unset}
input[type=submit]{padding:2px 6px}
.ltr table.layout label,.ltr label.jsonly{margin-left:8px}
.rtl table.layout label,.rtl label.jsonly{margin-right:8px}
#menu{padding:0 0 30px 0}
.ltr .logout{right:0;left:auto;margin-top:.5em}
.rtl .logout{left:0;right:auto;margin-top:.5em}

View File

@@ -2,8 +2,8 @@
* @package Adminer.css - Theme CSS for Adminer --- [theme dark] blue B (with icons)
*
*//*!
* @version 4.17.1.2
* @date Thu, 27 Feb 2025 09:28:32 +0100
* @version 5.0.4.1
* @date Wed, 12 Mar 2025 21:35:32 +0100
* @author Robert Mesaros
* @copyright Copyright 2025 Robert Mesaros, rmSOFT, Slovakia
* @web https://www.rmsoft.sk
@@ -35,10 +35,6 @@
* Modified icons by Robert Mesaros
*
*/
#menu{padding:0 0 30px 0}
.ltr .logout{right:0;left:auto;margin-top:.5em}
.rtl .logout{left:0;right:auto;margin-top:.5em}
.rtl table.layout tbody{direction:ltr}
html{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}
*,*:before,*:after{box-sizing:inherit}
body{color:#829bb0;background:#002240;font-family:Verdana,Arial,Helvetica,sans-serif;font-weight:normal;cursor:default;margin:0}
@@ -50,6 +46,9 @@ img{width:100%;max-width:100%}
#menu h1{background-color:#1d4e78}
#menu h1{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAdCAYAAAC9pNwMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozNDA3NDEwQ0Y0MkQxMUVGODA4RUNENTRFQzJENUU4RCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozNDA3NDEwQkY0MkQxMUVGODA4RUNENTRFQzJENUU4RCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRTREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Ph59M4AAAAPFSURBVHja7JZrSFNRHMDvvVvq1mNlucBK0g/lh+Us6oPrU0ERRFgRUqYUVEb2qTJ0vko0ZbMHiBT0sizSXEUfJGzN1CjBQLPCR/RwSYKp23RO3e527/r/57mxxpblhCD8w59z7t2553f+zx36Ulk5FYxkZpyiijVahUgkqnc62cu5arUGXrMl2tIkhmGuu91uGp4HXre0qB490A3C3IXfMVSQojl/QQYAHUzlNtvYPBhl2Xn5672gqBFxSmXF0WPpCTCfg+/EwUDBwkixeM4TmqZjzSbTFU1J8W00RiaTtUxMTJSfzctFd4Yq49eGJ6ekNETHxGyG50jQkWDAcoA+BqjSbDaXA/QqvBtFBWg6QGuJtSaapr7jB7AWrV0C6pguWAZurIeNFCaTqUxbUnwd3lkRAjoO0JswStApEGs1jJs4jusw9vTcEcI7LTBA3wA02mI2X/WFgvIIxCQC6EmIdQ7P898qb1Xs7O7qGiVrWWaa4C5PZopEy6RSKQfTYS8oRUYO1i3Hh4e6mlSA2sjhLHgwMdkoA04lI1noV8BVn/Nzsu/iFHTP2cIiHSTR9tNZaqYgP28/iecv4nA4ajmXi7NYLKPkcFbiDYomdcxNVVoul6s9JytzC/mYWxEVtfDQkbQKiUSyw26368/k5iTBexvZSxA0bD4Zx0An0E4B3Nfz5cu+zs4OJ+tgQwOBlfHxcSujo7MHBwfTLpZq69Cdq2NjFyWnpFaGhYVtA3hdU2PD4ecGQ78AhxjnQi6o29va1lVX3TNibAUwniSyq7PT+qKxcQjmduEHX0lQqSIgUZaOj4+FwyM2ipEP3d1msHRvQdG5GoQnqDYWAviEYDmErw/G1t7e3hAYQwiY+tm5Pn36aCdusATS+QsWDOBa8ArWInqGga6FltnQzcPDlrKvRmMTKSMRroXQ3AXd3fzq5ZCvQZ7kOnb8ONQXbYd+6/pNmBd70pXnfHPBAy8pKsojUNYruzmSEwzp0e5fwNCBFIFc7CXMZHbzIn9JT9wrJA/nVVasv8084PvVVVvftLbavIPvK6kHDqoUa9Zc+03J8V6WTike8FzpXJ4UtzUQOEIux98oCAdHzYCIJzsQw5M6s0LC+D01NIPxmQQz1D+SWfAs+D8FO1mn6w9uHUJ90zPSQOAvcdWOxERD4q5dSwjA/0KxuNmg1294/+7tGLlFuIOy+NbNG0b4s3YSSwIqyzr4Z/qnlv7+/iE/N42/FjokJBQ3lmI7JteUQK5E0Ajp6fZgLUaw0LNDp7juuomL2WCtRfkhwACjULOQ0RiwkAAAAABJRU5ErkJggg==");background-repeat:no-repeat;mix-blend-mode:difference}
#menu h1:hover{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAdCAYAAAC9pNwMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQUNCOTdFQkY0MkQxMUVGOUM0OUMyQTRDNjAyNzhENiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQUNCOTdFQUY0MkQxMUVGOUM0OUMyQTRDNjAyNzhENiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRTREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pq1mg9cAAAQtSURBVHja7JZdTFxFFIDP3J9dCgqUQimQIlBSWNoCNfVBYmo0jX9Jg014aYrWFzWGRl9MTHzpiy8k2kbrm9qUWtMaY9S2RqV9ADQm9o/+pHsvhW5Lw8/iLu6PC9yfvTOeWWbbC9ktlPWRk5ydvWfmzjfnzJkzlxz+7HNYSpIeD1QEAtB2+kew8vKgwdXn9Wsw1uR7tQTg+zhjfRs0fTeazWCT71ARwLt8jANgn0nMNO+9d+82nw6VSZCj3PE1VhcDnJIBpDnG8tC0TmvYvC8N5YJ9yq6C/L4/6je9jo8eVJITOMjY9lJCdBUdn6D0Sq0+9B6alTpZ7okwNrjGrzWjPnkwHO4oJKR8h8fzJfaXcLiUA3TLWkJ+x+WvQeglhL6N5jhqZIqxbyo1vQP/z6GOW5QN8nfI/KtrOVhZLogwllIuE4xVo6eXEJo3TumFOn2oS0D/Rv23WtPfxPYxVCvU5DuL41pMAOOWbf+ENu4sWR4YgUlVBUdRQHIcKJPlEQyvGqT02mLofC6BhRrFBPuhEOAZG20HJoOvHItEJtEeQ7WXFWrFtmGq+gm4+NLL6DUF23Ei3O4hpLRKVXkY/nFBRSKDjUlVxR8+Coc7BTSEGuZZr8w7xN6nlBZhS7LBqWHc3n/kyAkxaV2osWG4RJKqrtRvOluu6S0PtvCBxCg9iZtsBSwrJBYXEdFgKTAhpFuW5aW8v4p6RoTV7Bwb23F848aLxYRUhn2NN0o13Sf6kukX6vWhT7E5zoMm+mwOTTGxgIzfCQT2+v03bcu0vNmoLa2tzTW1tR+GpsNvHeru/pVP0FlcXHG4YsMFflSweEwdjUaf/2AyeEtEhWFincMM2/XzzOxzHaOjf6HNSIP5Sio1vz8+0NcXdncslqfb2sokSSqfTSRKRMbGTkSjE6hb0GM/h+8rKvoOwTtFAiUtxkYNQqI3TYNHkztlusEwMjJsiDMXzQZ+vLCQZy1gVFQxiWQ+u9P29g/EMMxNdxsbfhm2rH4+FHWWg6s0/QC2B0W1WjBvCvxOV9fXGHUD9zn5kD1el0oy6tzPhdM1tQD9A/ydWI0+9KKA8uShYogtkkpKJ9UCsKKoW7N56pIU0HGonDaMtG4H6OkBkVBxETUmgOljNZfxiPKfb0+dfGHw8uXE4lW55bX9b7Rt3bbtC/eR4wXFJY7rHC9dG/hPQX4BD820WHVGcNn69fHUTSPL9ydXDWPFF0wKLMkSB89wcPfHn9BMA03TnF0MxgKwYnDO9/EqeBW8Cl4Ati07ufTXD0ufb/J/gBW8Ejfvbm8/375nT6kAZB6oKH+e7+196sb1azPuC33FHh87+tVd/AKxhSdZ1bJMeq73t0gwGOT3duJR6nLGr1aPx8snzuflWFxr2ULpiAt++mEfDI8CTtdsb7p2Z9tmEWIrV2+5/CfAAOVxxSK4gGWJAAAAAElFTkSuQmCC");mask-image:linear-gradient(black, transparent);-webkit-mask-image:linear-gradient(black, transparent);mix-blend-mode:unset;background-color:unset}
.rtl table.layout tbody td{display:flex}
.rtl table.layout~table thead th:first-child,.rtl table.layout~table tbody td:first-child{text-align:right !important}
.rtl table.layout~table thead th:last-child,.rtl table.layout~table tbody td:last-child{text-align:left !important}
h1{padding:.6em .4em;background:#1d4e78;border:1px solid #f2ddaf;text-align:left}
#h1{color:#fff}
.version{color:#ddd;margin-left:8px}
@@ -100,7 +99,7 @@ code{background:#81a0bc;padding:.2em .5em}
table code{font-size:130%;background:#154167;padding:.1em .3em}
code.jush-sql{background:#c5d8e9}
.rtl p code.jush-sql{background-position:right;clear:right;float:right}
pre.sqlarea{background:#a7c3dc;padding:5px}
pre{background:#a7c3dc !important;padding:5px}
textarea{font-size:120%}
.ltr p.count{font-size:90%;margin:.8em 20px 8px 0}
.rtl p.count{font-size:90%;margin:.8em 0 8px 20px}
@@ -120,12 +119,12 @@ table{border-spacing:0}
table,td,th{border:0;border-collapse:separate}
.ltr table{margin:1.9em 0 0 0}
.rtl table{margin:1.9em 0 0 0}
.rtl table tbody td,.rtl table tbody th{text-align:right}
.rtl table tbody td,.rtl table tbody th{text-align:right !important}
.ltr table thead td:first-child,.ltr table thead th:first-child{border-left:1px solid #1e5687}
.rtl table thead td:first-child,.rtl table thead th:first-child{border-right:1px solid #1e5687}
table thead td,table thead th{height:1.6em;border-top:1px solid #1e5687;border-bottom:1px solid #1e5687}
.ltr table thead td,.ltr table thead th{border-right:1px solid #1e5687}
.rtl table thead td,.rtl table thead th{border-left:1px solid #1e5687;text-align:right !important}
.rtl table thead td,.rtl table thead th{border-left:1px solid #1e5687}
table tbody tr:first-child td,table tbody tr:first-child th{border-top:1px solid #1e5687}
.ltr table tbody td:first-child,.ltr table tbody th:first-child{border-left:1px solid #1e5687}
.rtl table tbody td:first-child,.rtl table tbody th:first-child{border-right:1px solid #1e5687}
@@ -422,9 +421,12 @@ input[type=radio]{margin-bottom:5px}
.rtl input[type=checkbox],.rtl input[type=radio],.rtl input[type=range],.rtl progress{margin-left:5px}
.ltr input[type=submit]{margin-right:10px}
.rtl input[type=submit]{margin-left:10px}
.ltr table.layout label,.ltr label.jsonly{margin-left:8px}
.rtl table.layout label,.rtl label.jsonly{margin-right:8px}
input,button,select,.sqlarea{border-radius:3px}
.sqlarea{background:#a7c3dc;font-size:105%}
fieldset a{line-height:unset}
input[type=submit]{padding:2px 6px}
.ltr table.layout label,.ltr label.jsonly{margin-left:8px}
.rtl table.layout label,.rtl label.jsonly{margin-right:8px}
#menu{padding:0 0 30px 0}
.ltr .logout{right:0;left:auto;margin-top:.5em}
.rtl .logout{left:0;right:auto;margin-top:.5em}

View File

@@ -2,8 +2,8 @@
* @package Adminer.css - Theme CSS for Adminer --- [theme light] blue B (with icons)
*
*//*!
* @version 4.17.1.2
* @date Thu, 27 Feb 2025 09:28:32 +0100
* @version 5.0.4.1
* @date Wed, 12 Mar 2025 21:35:32 +0100
* @author Robert Mesaros
* @copyright Copyright 2025 Robert Mesaros, rmSOFT, Slovakia
* @web https://www.rmsoft.sk
@@ -35,10 +35,6 @@
* Modified icons by Robert Mesaros
*
*/
#menu{padding:0 0 30px 0}
.ltr .logout{right:0;left:auto;margin-top:.5em}
.rtl .logout{left:0;right:auto;margin-top:.5em}
.rtl table.layout tbody{direction:ltr}
html{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}
*,*:before,*:after{box-sizing:inherit}
body{color:#000;background:#82a7c0;font-family:Verdana,Arial,Helvetica,sans-serif;font-weight:normal;cursor:default;margin:0}
@@ -49,6 +45,9 @@ img{width:100%;max-width:100%}
#menu #h1{margin-left:10px}
#menu h1{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAdCAYAAAC9pNwMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozNDA3NDEwQ0Y0MkQxMUVGODA4RUNENTRFQzJENUU4RCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozNDA3NDEwQkY0MkQxMUVGODA4RUNENTRFQzJENUU4RCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRTREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Ph59M4AAAAPFSURBVHja7JZrSFNRHMDvvVvq1mNlucBK0g/lh+Us6oPrU0ERRFgRUqYUVEb2qTJ0vko0ZbMHiBT0sizSXEUfJGzN1CjBQLPCR/RwSYKp23RO3e527/r/57mxxpblhCD8w59z7t2553f+zx36Ulk5FYxkZpyiijVahUgkqnc62cu5arUGXrMl2tIkhmGuu91uGp4HXre0qB490A3C3IXfMVSQojl/QQYAHUzlNtvYPBhl2Xn5672gqBFxSmXF0WPpCTCfg+/EwUDBwkixeM4TmqZjzSbTFU1J8W00RiaTtUxMTJSfzctFd4Yq49eGJ6ekNETHxGyG50jQkWDAcoA+BqjSbDaXA/QqvBtFBWg6QGuJtSaapr7jB7AWrV0C6pguWAZurIeNFCaTqUxbUnwd3lkRAjoO0JswStApEGs1jJs4jusw9vTcEcI7LTBA3wA02mI2X/WFgvIIxCQC6EmIdQ7P898qb1Xs7O7qGiVrWWaa4C5PZopEy6RSKQfTYS8oRUYO1i3Hh4e6mlSA2sjhLHgwMdkoA04lI1noV8BVn/Nzsu/iFHTP2cIiHSTR9tNZaqYgP28/iecv4nA4ajmXi7NYLKPkcFbiDYomdcxNVVoul6s9JytzC/mYWxEVtfDQkbQKiUSyw26368/k5iTBexvZSxA0bD4Zx0An0E4B3Nfz5cu+zs4OJ+tgQwOBlfHxcSujo7MHBwfTLpZq69Cdq2NjFyWnpFaGhYVtA3hdU2PD4ecGQ78AhxjnQi6o29va1lVX3TNibAUwniSyq7PT+qKxcQjmduEHX0lQqSIgUZaOj4+FwyM2ipEP3d1msHRvQdG5GoQnqDYWAviEYDmErw/G1t7e3hAYQwiY+tm5Pn36aCdusATS+QsWDOBa8ArWInqGga6FltnQzcPDlrKvRmMTKSMRroXQ3AXd3fzq5ZCvQZ7kOnb8ONQXbYd+6/pNmBd70pXnfHPBAy8pKsojUNYruzmSEwzp0e5fwNCBFIFc7CXMZHbzIn9JT9wrJA/nVVasv8084PvVVVvftLbavIPvK6kHDqoUa9Zc+03J8V6WTike8FzpXJ4UtzUQOEIux98oCAdHzYCIJzsQw5M6s0LC+D01NIPxmQQz1D+SWfAs+D8FO1mn6w9uHUJ90zPSQOAvcdWOxERD4q5dSwjA/0KxuNmg1294/+7tGLlFuIOy+NbNG0b4s3YSSwIqyzr4Z/qnlv7+/iE/N42/FjokJBQ3lmI7JteUQK5E0Ajp6fZgLUaw0LNDp7juuomL2WCtRfkhwACjULOQ0RiwkAAAAABJRU5ErkJggg==");background-repeat:no-repeat}
#menu h1:hover{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAdCAYAAAC9pNwMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQUNCOTdFQkY0MkQxMUVGOUM0OUMyQTRDNjAyNzhENiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQUNCOTdFQUY0MkQxMUVGOUM0OUMyQTRDNjAyNzhENiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRTREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFODREQjFFMzE2RjRFRjExOTIyNkVEQzE2RkYzQkNDRCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pq1mg9cAAAQtSURBVHja7JZdTFxFFIDP3J9dCgqUQimQIlBSWNoCNfVBYmo0jX9Jg014aYrWFzWGRl9MTHzpiy8k2kbrm9qUWtMaY9S2RqV9ADQm9o/+pHsvhW5Lw8/iLu6PC9yfvTOeWWbbC9ktlPWRk5ydvWfmzjfnzJkzlxz+7HNYSpIeD1QEAtB2+kew8vKgwdXn9Wsw1uR7tQTg+zhjfRs0fTeazWCT71ARwLt8jANgn0nMNO+9d+82nw6VSZCj3PE1VhcDnJIBpDnG8tC0TmvYvC8N5YJ9yq6C/L4/6je9jo8eVJITOMjY9lJCdBUdn6D0Sq0+9B6alTpZ7okwNrjGrzWjPnkwHO4oJKR8h8fzJfaXcLiUA3TLWkJ+x+WvQeglhL6N5jhqZIqxbyo1vQP/z6GOW5QN8nfI/KtrOVhZLogwllIuE4xVo6eXEJo3TumFOn2oS0D/Rv23WtPfxPYxVCvU5DuL41pMAOOWbf+ENu4sWR4YgUlVBUdRQHIcKJPlEQyvGqT02mLofC6BhRrFBPuhEOAZG20HJoOvHItEJtEeQ7WXFWrFtmGq+gm4+NLL6DUF23Ei3O4hpLRKVXkY/nFBRSKDjUlVxR8+Coc7BTSEGuZZr8w7xN6nlBZhS7LBqWHc3n/kyAkxaV2osWG4RJKqrtRvOluu6S0PtvCBxCg9iZtsBSwrJBYXEdFgKTAhpFuW5aW8v4p6RoTV7Bwb23F848aLxYRUhn2NN0o13Sf6kukX6vWhT7E5zoMm+mwOTTGxgIzfCQT2+v03bcu0vNmoLa2tzTW1tR+GpsNvHeru/pVP0FlcXHG4YsMFflSweEwdjUaf/2AyeEtEhWFincMM2/XzzOxzHaOjf6HNSIP5Sio1vz8+0NcXdncslqfb2sokSSqfTSRKRMbGTkSjE6hb0GM/h+8rKvoOwTtFAiUtxkYNQqI3TYNHkztlusEwMjJsiDMXzQZ+vLCQZy1gVFQxiWQ+u9P29g/EMMxNdxsbfhm2rH4+FHWWg6s0/QC2B0W1WjBvCvxOV9fXGHUD9zn5kD1el0oy6tzPhdM1tQD9A/ydWI0+9KKA8uShYogtkkpKJ9UCsKKoW7N56pIU0HGonDaMtG4H6OkBkVBxETUmgOljNZfxiPKfb0+dfGHw8uXE4lW55bX9b7Rt3bbtC/eR4wXFJY7rHC9dG/hPQX4BD820WHVGcNn69fHUTSPL9ydXDWPFF0wKLMkSB89wcPfHn9BMA03TnF0MxgKwYnDO9/EqeBW8Cl4Ati07ufTXD0ufb/J/gBW8Ejfvbm8/375nT6kAZB6oKH+e7+196sb1azPuC33FHh87+tVd/AKxhSdZ1bJMeq73t0gwGOT3duJR6nLGr1aPx8snzuflWFxr2ULpiAt++mEfDI8CTtdsb7p2Z9tmEWIrV2+5/CfAAOVxxSK4gGWJAAAAAElFTkSuQmCC")}
.rtl table.layout tbody td{display:flex}
.rtl table.layout~table thead th:first-child,.rtl table.layout~table tbody td:first-child{text-align:right !important}
.rtl table.layout~table thead th:last-child,.rtl table.layout~table tbody td:last-child{text-align:left !important}
h1{padding:.6em .4em;background:#1d5377;border:1px solid #f2ddaf;text-align:left}
#h1{color:#fff}
.version{color:#ddd;margin-left:8px}
@@ -99,7 +98,7 @@ code{background:#93b3c8;padding:.2em .5em}
table code{font-size:130%;background:#bfd9eb;padding:.1em .3em}
code.jush-sql{background:#d8e9f4}
.rtl p code.jush-sql{background-position:right;clear:right;float:right}
pre.sqlarea{background:#aac6d8;padding:5px}
pre{background:#aac6d8 !important;padding:5px}
textarea{font-size:120%}
.ltr p.count{font-size:90%;margin:.8em 20px 8px 0}
.rtl p.count{font-size:90%;margin:.8em 0 8px 20px}
@@ -119,12 +118,12 @@ table{border-spacing:0}
table,td,th{border:0;border-collapse:separate}
.ltr table{margin:1.9em 0 0 0}
.rtl table{margin:1.9em 0 0 0}
.rtl table tbody td,.rtl table tbody th{text-align:right}
.rtl table tbody td,.rtl table tbody th{text-align:right !important}
.ltr table thead td:first-child,.ltr table thead th:first-child{border-left:1px solid #0e344e}
.rtl table thead td:first-child,.rtl table thead th:first-child{border-right:1px solid #0e344e}
table thead td,table thead th{height:1.6em;border-top:1px solid #0e344e;border-bottom:1px solid #0e344e}
.ltr table thead td,.ltr table thead th{border-right:1px solid #0e344e}
.rtl table thead td,.rtl table thead th{border-left:1px solid #0e344e;text-align:right !important}
.rtl table thead td,.rtl table thead th{border-left:1px solid #0e344e}
table tbody tr:first-child td,table tbody tr:first-child th{border-top:1px solid #527d9a}
.ltr table tbody td:first-child,.ltr table tbody th:first-child{border-left:1px solid #527d9a}
.rtl table tbody td:first-child,.rtl table tbody th:first-child{border-right:1px solid #527d9a}
@@ -421,9 +420,12 @@ input[type=radio]{margin-bottom:5px}
.rtl input[type=checkbox],.rtl input[type=radio],.rtl input[type=range],.rtl progress{margin-left:5px}
.ltr input[type=submit]{margin-right:10px}
.rtl input[type=submit]{margin-left:10px}
.ltr table.layout label,.ltr label.jsonly{margin-left:8px}
.rtl table.layout label,.rtl label.jsonly{margin-right:8px}
input,button,select,.sqlarea{border-radius:3px}
.sqlarea{background:#aac6d8;font-size:105%}
fieldset a{line-height:unset}
input[type=submit]{padding:2px 6px}
.ltr table.layout label,.ltr label.jsonly{margin-left:8px}
.rtl table.layout label,.rtl label.jsonly{margin-right:8px}
#menu{padding:0 0 30px 0}
.ltr .logout{right:0;left:auto;margin-top:.5em}
.rtl .logout{left:0;right:auto;margin-top:.5em}

View File

@@ -20,7 +20,7 @@ if ($adminer->homepage()) {
foreach (table_status() as $table => $row) {
$name = $adminer->tableName($row);
if (isset($row["Engine"]) && $name != "") {
if ($name != "") {
echo '<tr><td>' . checkbox("tables[]", $table, in_array($table, (array) $_POST["tables"], true));
echo "<th><a href='" . h(ME) . 'select=' . urlencode($table) . "'>$name</a>";
$val = format_number($row["Rows"]);

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;
}
@@ -90,7 +92,10 @@ class Adminer {
}
function tableName($tableStatus) {
return h($tableStatus["Comment"] != "" ? $tableStatus["Comment"] : $tableStatus["Name"]);
return h(isset($tableStatus["Engine"])
? ($tableStatus["Comment"] != "" ? $tableStatus["Comment"] : $tableStatus["Name"])
: "" // ignore views
);
}
function fieldName($field, $order = 0) {
@@ -208,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;
@@ -623,6 +627,9 @@ qsl('div').onclick = whisperClick;", "")
}
}
function syntaxHighlighting($tables) {
}
function databasesPrint($missing) {
}
@@ -632,7 +639,7 @@ qsl('div').onclick = whisperClick;", "")
foreach ($tables as $row) {
echo '<li>';
$name = $this->tableName($row);
if (isset($row["Engine"]) && $name != "") { // ignore views and tables without name
if ($name != "") { // ignore tables without name
echo "<a href='" . h(ME) . 'select=' . urlencode($row["Name"]) . "'"
. bold($_GET["select"] == $row["Name"] || $_GET["edit"] == $row["Name"], "select")
. " title='" . lang('Select data') . "'>$name</a>\n"

1
externals/PhpShrink vendored Submodule

Submodule externals/PhpShrink added at b6fc11da47

2
externals/jush vendored

View File

@@ -12,8 +12,6 @@
<rule ref="PSR12">
<exclude name="Generic.Whitespace.DisallowTabIndent"/><!-- Replaced by: Generic.Whitespace.DisallowSpaceIndent -->
<exclude name="PSR1.Files.SideEffects.FoundWithSymbols"/>
<exclude name="PSR12.Operators.OperatorSpacing.NoSpaceBefore"/>
<exclude name="PSR12.Operators.OperatorSpacing.NoSpaceAfter"/>
<exclude name="PSR1.Classes.ClassDeclaration.MultipleClasses"/>
<exclude name="PSR2.Classes.ClassDeclaration.OpenBraceNewLine"/><!-- Replaced by: Generic.Classes.OpeningBraceSameLine -->
<exclude name="PSR2.Classes.PropertyDeclaration.Underscore"/>
@@ -24,6 +22,8 @@
<!-- More readable. -->
<exclude name="PSR12.Files.FileHeader.SpacingAfterBlock"/>
<exclude name="PSR12.Classes.OpeningBraceSpace.Found"/>
<exclude name="PSR12.Operators.OperatorSpacing.NoSpaceBefore"/>
<exclude name="PSR12.Operators.OperatorSpacing.NoSpaceAfter"/>
<exclude name="Squiz.WhiteSpace.ControlStructureSpacing.SpacingBeforeClose"/>
<!-- Saves bytes. -->
@@ -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>
@@ -45,7 +53,7 @@
<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="310"/>
<property name="lineLimit" value="250"/>
</properties>
<exclude-pattern>adminer/lang/</exclude-pattern>
</rule>
@@ -108,4 +116,21 @@
<rule ref="Squiz.WhiteSpace.LanguageConstructSpacing"/>
<rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing"/>
<rule ref="Squiz.WhiteSpace.ObjectOperatorSpacing"/>
<!--
This is slow and has false positives but it's useful occasionally.
https://github.com/PHPCompatibility/PHPCompatibility
<rule ref="PHPCompatibility"/>
<config name="testVersion" value="5.3-"/>
<rule ref="PHPCompatibility.Extensions.RemovedExtensions">
<exclude name="PHPCompatibility.Extensions.RemovedExtensions.mysql_DeprecatedRemoved"/>
<exclude name="PHPCompatibility.Extensions.RemovedExtensions.ibaseRemoved"/>
</rule>
<rule ref="PHPCompatibility.Constants.RemovedConstants">
<exclude-pattern>adminer/plugins/drivers/firebird.php</exclude-pattern>
</rule>
<rule ref="PHPCompatibility.FunctionUse.RemovedFunctions">
<exclude-pattern>adminer/plugins/drivers/firebird.php</exclude-pattern>
</rule>
-->
</ruleset>

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

@@ -143,7 +143,12 @@ if (isset($_GET["clickhouse"])) {
function __construct($connection) {
parent::__construct($connection);
$this->types = array( //! arrays
lang('Numbers') => array("Int8" => 3, "Int16" => 5, "Int32" => 10, "Int64" => 19, "UInt8" => 3, "UInt16" => 5, "UInt32" => 10, "UInt64" => 20, "Float32" => 7, "Float64" => 16, 'Decimal' => 38, 'Decimal32' => 9, 'Decimal64' => 18, 'Decimal128' => 38),
lang('Numbers') => array(
"Int8" => 3, "Int16" => 5, "Int32" => 10, "Int64" => 19,
"UInt8" => 3, "UInt16" => 5, "UInt32" => 10, "UInt64" => 20,
"Float32" => 7, "Float64" => 16,
'Decimal' => 38, 'Decimal32' => 9, 'Decimal64' => 18, 'Decimal128' => 38,
),
lang('Date and time') => array("Date" => 13, "DateTime" => 20),
lang('Strings') => array("String" => 0),
lang('Binary') => array("FixedString" => 0),

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

@@ -1,7 +1,7 @@
<?php
namespace Adminer;
$drivers["mongo"] = "MongoDB (alpha)";
add_driver("mongo", "MongoDB (alpha)");
if (isset($_GET["mongo"])) {
define('Adminer\DRIVER', "mongo");
@@ -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) {
@@ -120,9 +120,8 @@ if (isset($_GET["mongo"])) {
function get_databases($flush) {
global $connection;
$return = array();
foreach ($connection->executeCommand(array('listDatabases' => 1)) as $dbs) {
foreach (connection()->executeCommand(array('listDatabases' => 1)) as $dbs) {
foreach ($dbs->databases as $db) {
$return[] = $db->name;
}
@@ -136,9 +135,8 @@ if (isset($_GET["mongo"])) {
}
function tables_list() {
global $connection;
$collections = array();
foreach ($connection->executeCommand(array('listCollections' => 1)) as $result) {
foreach (connection()->executeCommand(array('listCollections' => 1)) as $result) {
$collections[$result->name] = 'table';
}
return $collections;
@@ -149,9 +147,8 @@ if (isset($_GET["mongo"])) {
}
function indexes($table, $connection2 = null) {
global $connection;
$return = array();
foreach ($connection->executeCommand(array('listIndexes' => $table)) as $index) {
foreach (connection()->executeCommand(array('listIndexes' => $table)) as $index) {
$descs = array();
$columns = array();
foreach (get_object_vars($index->key) as $column => $type) {
@@ -169,7 +166,7 @@ if (isset($_GET["mongo"])) {
}
function fields($table) {
global $driver;
$driver = driver();
$fields = fields_from_edit();
if (!$fields) {
$result = $driver->select($table, array("*"), null, null, array(), 10);
@@ -198,9 +195,8 @@ if (isset($_GET["mongo"])) {
}
function found_rows($table_status, $where) {
global $connection;
$where = where_to_query($where);
$toArray = $connection->executeCommand(array('count' => $table_status['Name'], 'query' => $where))->toArray();
$toArray = connection()->executeCommand(array('count' => $table_status['Name'], 'query' => $where))->toArray();
return $toArray[0]->n;
}
@@ -225,7 +221,6 @@ if (isset($_GET["mongo"])) {
}
function where_to_query($whereAnd = array(), $whereOr = array()) {
global $adminer;
$data = array();
foreach (array('and' => $whereAnd, 'or' => $whereOr) as $type => $where) {
if (is_array($where)) {
@@ -235,7 +230,7 @@ if (isset($_GET["mongo"])) {
list(, $class, $val) = $match;
$val = new $class($val);
}
if (!in_array($op, $adminer->operators)) {
if (!in_array($op, adminer()->operators)) {
continue;
}
if (preg_match('~^\(f\)(.+)~', $op, $match)) {
@@ -409,13 +404,11 @@ if (isset($_GET["mongo"])) {
}
function last_id() {
global $connection;
return $connection->last_id;
return connection()->last_id;
}
function error() {
global $connection;
return h($connection->error);
return h(connection()->error);
}
function collations() {
@@ -423,13 +416,11 @@ if (isset($_GET["mongo"])) {
}
function logged_user() {
global $adminer;
$credentials = $adminer->credentials();
$credentials = adminer()->credentials();
return $credentials[1];
}
function connect($credentials) {
global $adminer;
$connection = new Db;
list($server, $username, $password) = $credentials;
@@ -442,7 +433,7 @@ if (isset($_GET["mongo"])) {
$options["username"] = $username;
$options["password"] = $password;
}
$db = $adminer->database();
$db = adminer()->database();
if ($db != "") {
$options["db"] = $db;
}
@@ -457,7 +448,7 @@ if (isset($_GET["mongo"])) {
}
function alter_indexes($table, $alter) {
global $connection;
$connection = connection();
foreach ($alter as $val) {
list($type, $name, $set) = $val;
if ($set == "DROP") {
@@ -514,17 +505,15 @@ if (isset($_GET["mongo"])) {
}
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
global $connection;
if ($table == "") {
$connection->_db->createCollection($name);
connection()->_db->createCollection($name);
return true;
}
}
function drop_tables($tables) {
global $connection;
foreach ($tables as $table) {
$response = $connection->_db->selectCollection($table)->drop();
$response = connection()->_db->selectCollection($table)->drop();
if (!$response['ok']) {
return false;
}
@@ -533,9 +522,8 @@ if (isset($_GET["mongo"])) {
}
function truncate_tables($tables) {
global $connection;
foreach ($tables as $table) {
$response = $connection->_db->selectCollection($table)->remove();
$response = connection()->_db->selectCollection($table)->remove();
if (!$response['ok']) {
return false;
}

View File

@@ -422,7 +422,7 @@ if (isset($_GET["simpledb"])) {
'max_redirects' => 0,
))));
if (!$file) {
$this->error = lang('Invalid credentials.');
$connection->error = lang('Invalid credentials.');
return false;
}
libxml_use_internal_errors(true);

View File

@@ -14,7 +14,7 @@ class AdminerDumpAlter {
}
}
function _database() {
private function database() {
// drop old tables
$query = "SELECT TABLE_NAME, ENGINE, TABLE_COLLATION, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE()";
echo "DELIMITER ;;
@@ -59,9 +59,8 @@ SELECT @adminer_alter;
if ($first) {
$first = false;
echo "SET @adminer_alter = '';\n\n";
register_shutdown_function(array($this, '_database'));
} else {
$this->_database();
$this->database();
}
return true;
}
@@ -75,7 +74,10 @@ SELECT @adminer_alter;
} else {
echo substr_replace($create, " IF NOT EXISTS", 12, 0) . ";\n\n";
// create procedure which iterates over original columns and adds new and removes old
$query = "SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, COLLATION_NAME, COLUMN_TYPE, EXTRA, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = " . Adminer\q($table) . " ORDER BY ORDINAL_POSITION";
$query = "SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, COLLATION_NAME, COLUMN_TYPE, EXTRA, COLUMN_COMMENT
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = " . Adminer\q($table) . "
ORDER BY ORDINAL_POSITION";
echo "DELIMITER ;;
CREATE PROCEDURE adminer_alter (INOUT alter_command text) BEGIN
DECLARE _column_name, _collation_name, after varchar(64) DEFAULT '';
@@ -159,4 +161,10 @@ DROP PROCEDURE adminer_alter;
return true;
}
}
function dumpFooter() {
if ($_POST["format"] == "sql_alter") {
$this->database();
}
}
}

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();

14
plugins/editor-views.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
/** Display views in Adminer Editor
* @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 AdminerEditorViews {
function tableName($tableStatus) {
return Adminer\h($tableStatus["Comment"] != "" ? $tableStatus["Comment"] : $tableStatus["Name"]);
}
}

View File

@@ -14,12 +14,18 @@ class AdminerForeignSystem {
"columns_priv" => array(array("table" => "user", "source" => array("Host", "User"), "target" => array("Host", "User"))),
"db" => array(array("table" => "user", "source" => array("Host", "User"), "target" => array("Host", "User"))),
"help_category" => array(array("table" => "help_category", "source" => array("parent_category_id"), "target" => array("help_category_id"))),
"help_relation" => array(array("table" => "help_topic", "source" => array("help_topic_id"), "target" => array("help_topic_id")), array("table" => "help_keyword", "source" => array("help_keyword_id"), "target" => array("help_keyword_id"))),
"help_relation" => array(
array("table" => "help_topic", "source" => array("help_topic_id"), "target" => array("help_topic_id")),
array("table" => "help_keyword", "source" => array("help_keyword_id"), "target" => array("help_keyword_id")),
),
"help_topic" => array(array("table" => "help_category", "source" => array("help_category_id"), "target" => array("help_category_id"))),
"procs_priv" => array(array("table" => "user", "source" => array("Host", "User"), "target" => array("Host", "User")), array("table" => "proc", "source" => array("Db", "Routine_name"), "target" => array("db", "name"))),
"tables_priv" => array(array("table" => "user", "source" => array("Host", "User"), "target" => array("Host", "User"))),
"time_zone_name" => array(array("table" => "time_zone", "source" => array("Time_zone_id"), "target" => array("Time_zone_id"))),
"time_zone_transition" => array(array("table" => "time_zone", "source" => array("Time_zone_id"), "target" => array("Time_zone_id")), array("table" => "time_zone_transition_type", "source" => array("Time_zone_id", "Transition_type_id"), "target" => array("Time_zone_id", "Transition_type_id"))),
"time_zone_transition" => array(
array("table" => "time_zone", "source" => array("Time_zone_id"), "target" => array("Time_zone_id")),
array("table" => "time_zone_transition_type", "source" => array("Time_zone_id", "Transition_type_id"), "target" => array("Time_zone_id", "Transition_type_id")),
),
"time_zone_transition_type" => array(array("table" => "time_zone", "source" => array("Time_zone_id"), "target" => array("Time_zone_id"))),
);
return $return[$table];

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

@@ -1,15 +1,12 @@
<?php
/** Pretty print JSON values in edit
* @link https://www.adminer.org/plugins/#use
* @author Christopher Chen
* @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 AdminerPrettyJsonColumn {
/** @var AdminerPlugin */
protected $adminer;
public function __construct($adminer) {
$this->adminer = $adminer;
}
private function testJson($value) {
if ((substr($value, 0, 1) == '{' || substr($value, 0, 1) == '[') && ($json = json_decode($value, true))) {
return $json;
@@ -21,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 '';
}
@@ -33,6 +30,5 @@ class AdminerPrettyJsonColumn {
$value = json_encode($json);
}
}
return $this->adminer->_callParent('processInput', array($field, $value, $function));
}
}

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

@@ -15,7 +15,15 @@ class AdminerTableStructure {
function tableStructurePrint($fields) {
echo "<div class='scrollable'>\n";
echo "<table class='nowrap odds'>\n";
echo "<thead><tr><th>" . Adminer\lang('Column') . "<th>" . Adminer\lang('Type') . "<th>" . Adminer\lang('Collation') . "<th>" . Adminer\lang('Nullable') . "<th>" . Adminer\lang('Default') . (Adminer\support("comment") ? "<th>" . Adminer\lang('Comment') : "") . "</thead>\n";
echo "<thead><tr>"
. "<th>" . Adminer\lang('Column')
. "<th>" . Adminer\lang('Type')
. "<th>" . Adminer\lang('Collation')
. "<th>" . Adminer\lang('Nullable')
. "<th>" . Adminer\lang('Default')
. (Adminer\support("comment") ? "<th>" . Adminer\lang('Comment') : "")
. "</thead>\n"
;
foreach ($fields as $field) {
echo "<tr><th>" . Adminer\h($field["field"]) . ($field["primary"] ? " (PRIMARY)" : "");
echo "<td><span>" . Adminer\h($field["full_type"]) . "</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

@@ -2,7 +2,9 @@ Adminer - Database management in a single PHP file
Adminer Editor - Data manipulation for end-users
https://www.adminer.org/
Supports: MySQL, MariaDB, PostgreSQL, SQLite, MS SQL, Oracle, MongoDB, Elasticsearch (plugin), SimpleDB (plugin), Firebird (plugin), ClickHouse (plugin)
Supports: MySQL, MariaDB, PostgreSQL, CockroachDB, SQLite, MS SQL, Oracle
Plugins for: Elasticsearch, SimpleDB, MongoDB, Firebird, ClickHouse
Requirements: PHP 5.3+
adminer/index.php - Run development version of Adminer
@@ -15,6 +17,6 @@ editor/sqlite.php - Development version of Editor with SQLite allowed
adminer/designs.php - Development version of Adminer with adminer.css switcher
compile.php - Create a single file version
lang.php - Update translations
tests/katalon.html - Katalon Automation Recorder test suite
tests/*.html - Katalon Recorder test suites
If downloaded from Git then run: git submodule update --init

352
tests/cocroachdb.html Normal file
View File

@@ -0,0 +1,352 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<title>Katalon CockroachDB</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<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>
<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=PostgreSQL</td></tr>
<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>//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>
<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>
<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=character varying</td></tr>
<tr><td>type</td><td>fields[1.1][length]</td><td>50</td></tr>
<tr><td>uncheck</td><td>name=comments</td><td></td></tr>
<tr><td>clickAndWait</td><td>name=comments</td><td></td></tr>
<tr><td>type</td><td>fields[1.1][comment]</td><td>Interpret</td></tr>
<tr><td>type</td><td>Comment</td><td>Interprets</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">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>
<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>multiple primary keys for table "interprets" are not allowed</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/?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>
<tr><td>type</td><td>name</td><td>albums</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=character varying</td></tr>
<tr><td>type</td><td>fields[1.11][length]</td><td>50</td></tr>
<tr><td>check</td><td>name=comments</td><td></td></tr>
<tr><td>type</td><td>fields[1.1][comment]</td><td>Interpret</td></tr>
<tr><td>type</td><td>fields[1.11][comment]</td><td>Album</td></tr>
<tr><td>type</td><td>Comment</td><td>Albums</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/?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>
<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/?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>
<tr><td>click</td><td>add[2]</td><td></td></tr>
<tr><td>type</td><td>fields[3][field]</td><td>albums</td></tr>
<tr><td>select</td><td>fields[3][type]</td><td>label=integer</td></tr>
<tr><td>type</td><td>fields[3][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[3][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">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>//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>
<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>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">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>
<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 has been inserted.</td><td></td></tr>
<tr><td>open</td><td>/adminer/?pgsql=localhost:26257&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&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 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/?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>
<tr><td>clickAndWait</td><td>clone</td><td></td></tr>
<tr><td>type</td><td>fields[id]</td><td>2</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>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" 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>
<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>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>
<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>
<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>
<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>
<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/?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>
<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/?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>
<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 "public"."interprets"</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">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>
<tr><td>type</td><td>fields[1][field]</td><td>interpret_name</td></tr>
<tr><td>select</td><td>fields[1][type]</td><td>label=character varying</td></tr>
<tr><td>type</td><td>fields[1][length]</td><td>50</td></tr>
<tr><td>type</td><td>fields[1.1][field]</td><td>album_title</td></tr>
<tr><td>select</td><td>fields[1.1][type]</td><td>label=character varying</td></tr>
<tr><td>type</td><td>fields[1.1][length]</td><td>50</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="definition"]').value = 'SELECT id FROM interprets;'</td><td></td></tr>
<tr><td>type</td><td>name</td><td>insert_album</td></tr>
<tr><td>select</td><td>name=language</td><td>label=sql</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Routine has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=insert_album</td><td></td></tr>
<tr><td>type</td><td>fields[interpret_name]</td><td>Michael Jackson</td></tr>
<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>
<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" 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>
<tr><td>chooseOkOnNextConfirmation</td><td>Are you sure?</td><td></td></tr>
<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>
<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>
<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>
<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>

408
tests/mariadb.html Normal file
View File

@@ -0,0 +1,408 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<title>Katalon MariaDB</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<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>
<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[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>//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>
<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>
<tr><td>type</td><td>name</td><td>adminer_test</td></tr>
<tr><td>select</td><td>collation</td><td>label=utf8mb4_general_ci</td></tr>
<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>
<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>
<tr><td>type</td><td>name</td><td>interprets</td></tr>
<tr><td>select</td><td>Engine</td><td>label=InnoDB</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=int</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=varchar</td></tr>
<tr><td>type</td><td>fields[1.1][length]</td><td>50</td></tr>
<tr><td>uncheck</td><td>name=comments</td><td></td></tr>
<tr><td>clickAndWait</td><td>name=comments</td><td></td></tr>
<tr><td>type</td><td>fields[1.1][comment]</td><td>Interpret</td></tr>
<tr><td>type</td><td>Comment</td><td>Interprets</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">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>
<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>name</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Multiple primary key defined</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">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>
<tr><td>select</td><td>partition_by</td><td>label=HASH</td></tr>
<tr><td>click</td><td>link=Partition by</td><td></td></tr>
<tr><td>type</td><td>partition</td><td>id</td></tr>
<tr><td>type</td><td>partitions</td><td>2</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>
<tr><td>clickAndWait</td><td>link=Alter table</td><td></td></tr>
<tr><td>select</td><td>partition_by</td><td>label=RANGE</td></tr>
<tr><td>type</td><td>partition_values[]</td><td>10</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>
<tr><td>clickAndWait</td><td>link=Alter table</td><td></td></tr>
<tr><td>select</td><td>partition_by</td><td>label=</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 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>
<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=int</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=int</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=varchar</td></tr>
<tr><td>type</td><td>fields[1.11][length]</td><td>50</td></tr>
<tr><td>check</td><td>name=comments</td><td></td></tr>
<tr><td>type</td><td>fields[1.1][comment]</td><td>Interpret</td></tr>
<tr><td>type</td><td>fields[1.11][comment]</td><td>Album</td></tr>
<tr><td>type</td><td>Comment</td><td>Albums</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/?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>
<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/?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>
<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=int</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/?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>
<tr><td>runScript</td><td>document.querySelector('[name="Statement"]').value = 'UPDATE interprets SET albums = albums + 1 WHERE id = NEW.interpret'</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/?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>//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>
<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>
<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/?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>
<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>open</td><td>/adminer/?server=localhost:3307&amp;username=ODBC&amp;db=adminer_test&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/?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>
<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/?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>
<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>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>
<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>
<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>
<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>
<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/?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>
<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">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>
<tr><td>type</td><td>objects[0]</td><td>adminer_test.*</td></tr>
<tr><td>click</td><td>grants[0][ALTER]</td><td></td></tr>
<tr><td>click</td><td>grants[0][CREATE]</td><td></td></tr>
<tr><td>click</td><td>//input[@name='grants[0][CREATE VIEW]']</td><td></td></tr>
<tr><td>click</td><td>grants[0][DELETE]</td><td></td></tr>
<tr><td>click</td><td>grants[0][DROP]</td><td></td></tr>
<tr><td>click</td><td>grants[0][INDEX]</td><td></td></tr>
<tr><td>click</td><td>grants[0][INSERT]</td><td></td></tr>
<tr><td>click</td><td>grants[0][REFERENCES]</td><td></td></tr>
<tr><td>click</td><td>grants[0][SELECT]</td><td></td></tr>
<tr><td>click</td><td>//input[@name='grants[0][SHOW VIEW]']</td><td></td></tr>
<tr><td>click</td><td>grants[0][UPDATE]</td><td></td></tr>
<tr><td>click</td><td>//input[@name='grants[0][CREATE TEMPORARY TABLES]']</td><td></td></tr>
<tr><td>click</td><td>//input[@name='grants[0][LOCK TABLES]']</td><td></td></tr>
<tr><td>click</td><td>//input[@name='grants[0][CREATE ROUTINE]']</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>User has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>//div[@id='content']/form/table/tbody/tr[td[1]='adminer_test']/td[3]/a</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop adminer_test@localhost?</td><td></td></tr>
<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>
<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>
<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>
<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">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>
<tr><td>select</td><td>INTERVAL_FIELD</td><td>label=DAY</td></tr>
<tr><td>type</td><td>INTERVAL_VALUE</td><td>1</td></tr>
<tr><td>click</td><td>ON_COMPLETION</td><td></td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="EVENT_DEFINITION"]').value = 'DELETE FROM albums WHERE interprets = 0'</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Event has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter</td><td></td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop no_albums?</td><td></td></tr>
<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>
<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>
<tr><td>type</td><td>fields[1][field]</td><td>interpret_name</td></tr>
<tr><td>select</td><td>fields[1][type]</td><td>label=varchar</td></tr>
<tr><td>type</td><td>fields[1][length]</td><td>50</td></tr>
<tr><td>type</td><td>fields[1.1][field]</td><td>album_title</td></tr>
<tr><td>select</td><td>fields[1.1][type]</td><td>label=varchar</td></tr>
<tr><td>type</td><td>fields[1.1][length]</td><td>50</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="definition"]').value = 'BEGIN\nSELECT id INTO @interpret FROM interprets WHERE name = interpret_name;\nIF @interpret IS NULL THEN\n INSERT INTO interprets (name) VALUES (interpret_name);\n SET @interpret = LAST_INSERT_ID();\nEND IF;\nINSERT INTO albums (interpret, title) VALUES (@interpret, album_title);\nEND'</td><td></td></tr>
<tr><td>type</td><td>name</td><td>insert_album</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Routine has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=insert_album</td><td></td></tr>
<tr><td>type</td><td>fields[interpret_name]</td><td>Michael Jackson</td></tr>
<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>
<tr><td>clickAndWait</td><td>link=adminer_test</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>
<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" 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>
<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>
<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>

280
tests/mssql.html Normal file
View File

@@ -0,0 +1,280 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<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>
<tbody>
<tr><td>open</td><td>/adminer/</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=MS SQL</td></tr>
<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>//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>
<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>
<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=int</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=varchar</td></tr>
<tr><td>type</td><td>fields[1.1][length]</td><td>50</td></tr>
<tr><td>uncheck</td><td>name=comments</td><td></td></tr>
<tr><td>clickAndWait</td><td>name=comments</td><td></td></tr>
<tr><td>type</td><td>fields[1.1][comment]</td><td>Interpret</td></tr>
<tr><td>type</td><td>Comment</td><td>Interprets</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">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>
<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>Table 'interprets' already has a primary key defined on it.</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/?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>
<tr><td>type</td><td>name</td><td>albums</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=int</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=varchar</td></tr>
<tr><td>type</td><td>fields[1.11][length]</td><td>50</td></tr>
<tr><td>check</td><td>name=comments</td><td></td></tr>
<tr><td>type</td><td>fields[1.1][comment]</td><td>Interpret</td></tr>
<tr><td>type</td><td>fields[1.11][comment]</td><td>Album</td></tr>
<tr><td>type</td><td>Comment</td><td>Albums</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/?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>
<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/?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>
<tr><td>click</td><td>add[2]</td><td></td></tr>
<tr><td>type</td><td>fields[3][field]</td><td>albums</td></tr>
<tr><td>select</td><td>fields[3][type]</td><td>label=int</td></tr>
<tr><td>type</td><td>fields[3][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[3][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">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>//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>
<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>
<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/?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>
<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>open</td><td>/adminer/?mssql=%28local%29&amp;username=ODBC&amp;db=adminer_test&amp;ns=dbo&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/?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>
<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/?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>
<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>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>
<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>
<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>
<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>
<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/?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>
<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/?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>
<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 [dbo].[interprets]</td><td></td></tr>
<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" 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>
<tr><td>chooseOkOnNextConfirmation</td><td>Are you sure?</td><td></td></tr>
<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>
<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>
<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

@@ -3,14 +3,12 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<title>katalon</title>
<title>Katalon MySQL</title>
</head>
<body>
<!-- The tests don't work with jush-textarea.js. Delete it first. -->
<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>
@@ -18,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>
@@ -37,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>
@@ -59,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>
@@ -75,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>
@@ -98,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>
@@ -121,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>
@@ -133,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>
@@ -150,50 +141,49 @@
<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>
<tr><td>type</td><td>name=Statement</td><td>UPDATE interprets SET albums = albums + 1 WHERE id = NEW.interpret</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="Statement"]').value = 'UPDATE interprets SET albums = albums + 1 WHERE id = NEW.interpret'</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>
<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=clause</td><td>interpret > 0</td></tr>
<tr><td>click</td><td>xpath=//input[@value='Save']</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>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Check has been created.</td><td></td></tr>
<tr><td>open</td><td>/adminer/?username=ODBC&amp;db=adminer_test&amp;check=albums&amp;name=albums_chk_1</td><td></td></tr>
<tr><td>verifyText</td><td>name=clause</td><td>(`interpret` > 0)</td></tr>
<tr><td>chooseOkOnNextConfirmation</td><td>Drop albums_chk_1?</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>type</td><td>select</td><td>SELECT albums.id, albums.title, interprets.name
FROM albums
LEFT JOIN interprets ON albums.interpret = interprets.id</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>
<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>
@@ -205,10 +195,9 @@ LEFT JOIN interprets ON albums.interpret = interprets.id</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>
<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>
@@ -217,10 +206,9 @@ LEFT JOIN interprets ON albums.interpret = interprets.id</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>
<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>
@@ -228,29 +216,26 @@ LEFT JOIN interprets ON albums.interpret = interprets.id</td></tr>
<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>
@@ -259,10 +244,9 @@ LEFT JOIN interprets ON albums.interpret = interprets.id</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>
<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>
@@ -271,10 +255,9 @@ LEFT JOIN interprets ON albums.interpret = interprets.id</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">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>
@@ -300,18 +283,16 @@ LEFT JOIN interprets ON albums.interpret = interprets.id</td></tr>
<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>
@@ -324,17 +305,16 @@ LEFT JOIN interprets ON albums.interpret = interprets.id</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">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>
<tr><td>select</td><td>INTERVAL_FIELD</td><td>label=DAY</td></tr>
<tr><td>type</td><td>INTERVAL_VALUE</td><td>1</td></tr>
<tr><td>click</td><td>ON_COMPLETION</td><td></td></tr>
<tr><td>type</td><td>EVENT_DEFINITION</td><td>DELETE FROM albums WHERE interprets = 0</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="EVENT_DEFINITION"]').value = 'DELETE FROM albums WHERE interprets = 0'</td><td></td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Event has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=Alter</td><td></td></tr>
@@ -342,10 +322,9 @@ LEFT JOIN interprets ON albums.interpret = interprets.id</td></tr>
<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>
@@ -355,14 +334,7 @@ LEFT JOIN interprets ON albums.interpret = interprets.id</td></tr>
<tr><td>type</td><td>fields[1.1][field]</td><td>album_title</td></tr>
<tr><td>select</td><td>fields[1.1][type]</td><td>label=varchar</td></tr>
<tr><td>type</td><td>fields[1.1][length]</td><td>50</td></tr>
<tr><td>type</td><td>definition</td><td>BEGIN
SELECT id INTO @interpret FROM interprets WHERE name = interpret_name;
IF @interpret IS NULL THEN
INSERT INTO interprets (name) VALUES (interpret_name);
SET @interpret = LAST_INSERT_ID();
END IF;
INSERT INTO albums (interpret, title) VALUES (@interpret, album_title);
END</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="definition"]').value = 'BEGIN\nSELECT id INTO @interpret FROM interprets WHERE name = interpret_name;\nIF @interpret IS NULL THEN\n INSERT INTO interprets (name) VALUES (interpret_name);\n SET @interpret = LAST_INSERT_ID();\nEND IF;\nINSERT INTO albums (interpret, title) VALUES (@interpret, album_title);\nEND'</td><td></td></tr>
<tr><td>type</td><td>name</td><td>insert_album</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Routine has been created.</td><td></td></tr>
@@ -370,51 +342,78 @@ END</td></tr>
<tr><td>type</td><td>fields[interpret_name]</td><td>Michael Jackson</td></tr>
<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, 1 row affected.</td><td></td></tr>
<tr><td>assertTextPresent</td><td>Routine has been called,</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=adminer_test</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>
<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>
@@ -426,61 +425,9 @@ END</td></tr>
<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">SQLite</td></tr>
</thead>
<tbody>
<tr><td>open</td><td>/adminer/sqlite.php</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>name=auth[password]</td><td></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>
<tr><td>type</td><td>name=name</td><td>adminer_test</td></tr>
<tr><td>click</td><td>css=input[type="submit"]</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Please use one of the extensions</td><td></td></tr>
<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>
<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>
<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>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>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>
<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>
@@ -489,5 +436,6 @@ END</td></tr>
<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>
</html>

352
tests/pgsql.html Normal file
View File

@@ -0,0 +1,352 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<title>Katalon PostgreSQL</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<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>
<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=PostgreSQL</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>type</td><td>name=auth[db]</td><td>adminer_test</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>
<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>
<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=character varying</td></tr>
<tr><td>type</td><td>fields[1.1][length]</td><td>50</td></tr>
<tr><td>uncheck</td><td>name=comments</td><td></td></tr>
<tr><td>clickAndWait</td><td>name=comments</td><td></td></tr>
<tr><td>type</td><td>fields[1.1][comment]</td><td>Interpret</td></tr>
<tr><td>type</td><td>Comment</td><td>Interprets</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">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>
<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>multiple primary keys for table "interprets" are not allowed</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/?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>
<tr><td>type</td><td>name</td><td>albums</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=character varying</td></tr>
<tr><td>type</td><td>fields[1.11][length]</td><td>50</td></tr>
<tr><td>check</td><td>name=comments</td><td></td></tr>
<tr><td>type</td><td>fields[1.1][comment]</td><td>Interpret</td></tr>
<tr><td>type</td><td>fields[1.11][comment]</td><td>Album</td></tr>
<tr><td>type</td><td>Comment</td><td>Albums</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/?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>
<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/?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>
<tr><td>click</td><td>add[2]</td><td></td></tr>
<tr><td>type</td><td>fields[3][field]</td><td>albums</td></tr>
<tr><td>select</td><td>fields[3][type]</td><td>label=integer</td></tr>
<tr><td>type</td><td>fields[3][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[3][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">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>//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>
<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>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">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>
<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>
<tr><td>open</td><td>/adminer/?pgsql=&amp;username=ODBC&amp;db=adminer_test&amp;ns=public&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 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/?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>
<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>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" 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>
<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>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>
<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>
<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>
<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>
<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/?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>
<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">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>
<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>
<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 "public"."interprets"</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">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>
<tr><td>type</td><td>fields[1][field]</td><td>interpret_name</td></tr>
<tr><td>select</td><td>fields[1][type]</td><td>label=character varying</td></tr>
<tr><td>type</td><td>fields[1][length]</td><td>50</td></tr>
<tr><td>type</td><td>fields[1.1][field]</td><td>album_title</td></tr>
<tr><td>select</td><td>fields[1.1][type]</td><td>label=character varying</td></tr>
<tr><td>type</td><td>fields[1.1][length]</td><td>50</td></tr>
<tr><td>runScript</td><td>document.querySelector('[name="definition"]').value = 'SELECT id FROM interprets;'</td><td></td></tr>
<tr><td>type</td><td>name</td><td>insert_album</td></tr>
<tr><td>select</td><td>name=language</td><td>label=sql</td></tr>
<tr><td>clickAndWait</td><td>//input[@value='Save']</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Routine has been created.</td><td></td></tr>
<tr><td>clickAndWait</td><td>link=insert_album</td><td></td></tr>
<tr><td>type</td><td>fields[interpret_name]</td><td>Michael Jackson</td></tr>
<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>
<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>
<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" 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>
<tr><td>chooseOkOnNextConfirmation</td><td>Are you sure?</td><td></td></tr>
<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>
<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>
<tbody>
<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>
<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>

276
tests/sqlite.html Normal file
View File

@@ -0,0 +1,276 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<title>Katalon SQLite</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<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>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>
<tr><td>type</td><td>name=name</td><td>adminer_test</td></tr>
<tr><td>click</td><td>css=input[type="submit"]</td><td></td></tr>
<tr><td>verifyTextPresent</td><td>Please use one of the extensions</td><td></td></tr>
<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>
</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>
</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>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>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