1
0
mirror of https://github.com/vrana/adminer.git synced 2025-09-03 03:13:00 +02:00

Compare commits

...

161 Commits

Author SHA1 Message Date
Jakub Vrana
8d7cb5954d Release 5.0.0 2025-03-07 09:40:15 +01:00
Jakub Vrana
47700f2763 PostgreSQL: Fix exporting foreign keys 2025-03-07 08:02:06 +01:00
Jakub Vrana
a4a8f48a9c PHPCS: Ignore compiled files 2025-03-07 07:56:35 +01:00
Jakub Vrana
770a77ac33 Wrap long lines 2025-03-07 07:44:26 +01:00
Jakub Vrana
8ceaf36de7 Editor: Fix getting fields 2025-03-07 07:17:05 +01:00
Jakub Vrana
517d2d1c2f MS SQL: Support computed columns 2025-03-07 06:42:27 +01:00
Jakub Vrana
af5d519266 SQLite: Support generated columns 2025-03-07 06:07:25 +01:00
Jakub Vrana
c045b20a8e Allow creating generated columns (bug #857) 2025-03-07 05:18:56 +01:00
Jakub Vrana
874307a27f Fix undefined variable 2025-03-07 04:56:31 +01:00
Jakub Vrana
c27b91a167 MySQL: Drop support for MySQL 4 2025-03-07 03:58:42 +01:00
Jakub Vrana
afe03ef720 MySQL: Display generated value in table structure 2025-03-07 03:58:33 +01:00
Jakub Vrana
c0e2ab22d5 Syntax highlight generated expressions 2025-03-06 19:47:05 +01:00
Jakub Vrana
7351980beb Skip generated columns in multi-edit (bug #882) 2025-03-06 19:32:19 +01:00
Jakub Vrana
7b5a20334d Don't allow inline edit of generated columns 2025-03-06 18:59:20 +01:00
Jakub Vrana
6262b120f5 PostgreSQL: Skip editing generated columns 2025-03-06 18:44:18 +01:00
Jakub Vrana
bd27ca0b2b Add comment 2025-03-06 18:36:26 +01:00
Jakub Vrana
aa7cf70d25 JS: Use || 2025-03-06 18:23:20 +01:00
Jakub Vrana
94a4f61db2 PHP: Use ?: 2025-03-06 18:12:22 +01:00
Jakub Vrana
dc50bf17ea SQLite: Remove useless condition 2025-03-06 17:55:45 +01:00
Jakub Vrana
f05f4b4cbc Change $jush to constant 2025-03-06 17:51:20 +01:00
Jakub Vrana
0541680d73 Move constants to namespace 2025-03-06 17:34:21 +01:00
Jakub Vrana
5a84ff7647 PostgreSQL: Display ? instead of -1 rows in table overview (bug #883) 2025-03-06 17:08:32 +01:00
Jakub Vrana
edd7c67797 Delete incorporated plugin 2025-03-06 14:59:48 +01:00
Jakub Vrana
c6f825a786 Move $enum_length to Driver 2025-03-06 14:51:24 +01:00
Jakub Vrana
f711135574 Move $inout to Driver 2025-03-06 14:49:08 +01:00
Jakub Vrana
2b16f51933 PDO: Support search by expression.
This reverts b848764.
2025-03-06 14:40:13 +01:00
Jakub Vrana
d268e0ebb4 ClickHouse: Check for allow_url_fopen 2025-03-06 14:30:50 +01:00
Jakub Vrana
5fdaae27dc Move possible drivers and JUSH to Driver 2025-03-06 14:27:58 +01:00
Jakub Vrana
049536da90 Mongo: Use $this->_conn 2025-03-06 14:10:05 +01:00
Jakub Vrana
bddce074fa Mongo: Add Driver outside of if 2025-03-06 14:08:19 +01:00
Jakub Vrana
347d9f1f55 Move on_actions to Driver 2025-03-06 14:04:47 +01:00
Jakub Vrana
a8feb00098 Move unsigned to Driver 2025-03-06 13:58:15 +01:00
Jakub Vrana
69d7d76dc5 Move operators, functions and grouping to Driver 2025-03-06 13:51:49 +01:00
Jakub Vrana
2f0cd4185b Move edit functions to Driver 2025-03-06 13:28:04 +01:00
Jakub Vrana
37a75f3759 Move types to Driver 2025-03-06 12:35:20 +01:00
Takashi SHIRAI
d2add4dd72 Fix the primary key for MS SQL
Signed-off-by: Takashi SHIRAI <shirai@nintendo.co.jp>
2025-03-06 08:54:59 +01:00
Jakub Vrana
f5d47d46a0 Use anonymous function 2025-03-05 17:08:29 +01:00
Jakub Vrana
e8d9a126be Rely on PHP 5.3 2025-03-05 17:05:19 +01:00
Jakub Vrana
12f0a4bc9a Inform about namespace use 2025-03-05 16:54:53 +01:00
Jakub Vrana
d9df9693e3 Code style: Add more checks 2025-03-05 16:33:22 +01:00
Jakub Vrana
873d6d50fd Code style: explain rules 2025-03-05 15:55:33 +01:00
Jakub Vrana
c873ceba17 Use PHP 5.3 functions 2025-03-05 15:54:13 +01:00
Jakub Vrana
0bf8861dd1 Plugins: Use namespace for driver functions 2025-03-05 15:54:08 +01:00
Jakub Vrana
137ac2396b Fix plugin autoloading 2025-03-05 15:39:48 +01:00
Jakub Vrana
755d7b47ac Code style: Check camel caps except in drivers 2025-03-05 15:37:16 +01:00
Jakub Vrana
dd947fc1ee Don't check code style in compiled files 2025-03-05 15:36:25 +01:00
Jakub Vrana
105999f62e Code style: Indent long statements 2025-03-05 15:01:21 +01:00
Jakub Vrana
ed5de27dd3 Code style: Indent long statements 2025-03-05 14:59:13 +01:00
Jakub Vrana
293e031498 Plugins: Add missing namespaces 2025-03-05 14:51:55 +01:00
Jakub Vrana
a7f097e78c Code style: Indent long statements 2025-03-05 14:51:17 +01:00
Jakub Vrana
af68e30742 Code style: Remove newline before } 2025-03-05 14:38:48 +01:00
Jakub Vrana
f820fa1c26 Mark abstract classes 2025-03-05 14:31:53 +01:00
Jakub Vrana
f468c095ae Make root namespace explicit 2025-03-05 14:25:09 +01:00
Jakub Vrana
c10b614ee1 Mongo: inline class names 2025-03-05 14:20:54 +01:00
Jakub Vrana
f5b255230b Don't require namespace in example 2025-03-05 14:15:32 +01:00
Jakub Vrana
54568ddef6 PDO: Support namespaces 2025-03-05 14:15:17 +01:00
Jakub Vrana
3da09dd31a Rename Min_ classes 2025-03-05 14:12:42 +01:00
Jakub Vrana
45ac930e06 Update todo 2025-03-05 13:45:42 +01:00
Jakub Vrana
e801753519 Remove extra newline 2025-03-05 13:45:23 +01:00
Jakub Vrana
a4e9f7b87b Fix tests 2025-03-05 13:31:50 +01:00
Jakub Vrana
35829eedaf Use namespace 2025-03-05 13:31:03 +01:00
Jakub Vrana
44c2e979f7 Compile: Support else after if (support) 2025-03-05 13:19:17 +01:00
Jakub Vrana
2a8b4009b1 Namespaces in compile 2025-03-05 13:14:21 +01:00
Jakub Vrana
6ceebc99df Add namespace in lang.php 2025-03-05 13:10:41 +01:00
Jakub Vrana
2f49bfb67e Return accidentally removed error message 2025-03-05 13:10:41 +01:00
Jakub Vrana
e1e085f312 Use namespace in callbacks 2025-03-05 13:10:40 +01:00
Jakub Vrana
50e7a65e6e Use namespaces in plugins 2025-03-05 13:10:40 +01:00
Jakub Vrana
52c5392089 PHP: Use namespace 2025-03-05 13:10:40 +01:00
Jakub Vrana
5a708df6ca Coding style: Check newline at {} 2025-03-05 13:10:40 +01:00
Jakub Vrana
c52ba0308e Specify coding style and follow it 2025-03-05 13:10:37 +01:00
Jakub Vrana
422668f2d7 Composer: Exclude drivers from classmap 2025-03-05 06:35:54 +01:00
Jakub Vrana
f0335f7f8b Hide Refresh link if it does nothing 2025-03-04 19:58:26 +01:00
Jakub Vrana
cc635acd20 Remove unnecessary function 2025-03-04 19:52:07 +01:00
Jakub Vrana
63dd38c44d PostgreSQL: Compute size of all databases (bug #881) 2025-03-04 19:40:42 +01:00
Jakub Vrana
e411c229ab Fix enum alignment 2025-03-04 18:53:01 +01:00
Jakub Vrana
b9d6529442 Remove margin from td pre 2025-03-04 18:46:28 +01:00
Jakub Vrana
0426bd4610 Designs: Fix logout button 2025-03-04 18:44:40 +01:00
Jakub Vrana
c7d283d262 Designs: Fix background of pre.jush 2025-03-04 18:34:07 +01:00
Jakub Vrana
d61678f5cb Reapply "Fix background color of <pre> used as edit field"
This reverts commit 9b25969fb2.
2025-03-04 18:11:32 +01:00
Jakub Vrana
94088474dd Design bilal-dark: Add missing icons 2025-03-04 18:10:23 +01:00
Jakub Vrana
9b25969fb2 Revert "Fix background color of <pre> used as edit field"
This reverts commit 0717bce535.
2025-03-04 11:04:26 +01:00
Jakub Vrana
996b178406 MySQL: Fix connecting with self-signed cert 2025-03-03 16:06:10 +01:00
Jakub Vrana
116827060f PostgreSQL, MS SQL, Oracle: Hide table actions for information_schema 2025-03-03 15:54:08 +01:00
Jakub Vrana
af87336116 Add TODO 2025-03-03 15:43:04 +01:00
jfonsato
17939b56c4 PostgreSQL: Show only accessible databases 2025-03-03 15:34:43 +01:00
Christian Weiske
d5a17835ff Elastic: Fix text search on boolean fields
When searching in all fields for a text value, an error was thrown
with ElasticSearch 7.17.23 when the index contains boolean fields:

> query_shard_exception: failed to create query:
> Can't parse boolean value [textvalue], expected [true] or [false]

This patch fixes that problem by skipping boolean fields when the
search word is not the string "true" or "false".
2025-03-03 10:40:38 +01:00
Matrixman
4967a40410 New version of design rmSOFT
New version of design rmSOFT
2025-03-03 09:36:21 +01:00
Jan Tojnar
4cdcb44bee Use more [] in doc-comments
Follow up to 42de70d032
2025-03-03 08:39:17 +01:00
Jakub Vrana
160beb726a MS SQL: Link help from sys tables 2025-03-03 08:18:20 +01:00
Jakub Vrana
fb3b23617d Don't autofocus computed fields in insert form 2025-03-03 06:34:02 +01:00
Jakub Vrana
dfe3cc1888 Warn about failed type export 2025-03-03 05:17:00 +01:00
Jakub Vrana
c1704d83c1 Add comment 2025-03-03 05:16:15 +01:00
Jakub Vrana
364a4bce1f Update todo 2025-02-28 17:28:35 +01:00
Jakub Vrana
d9bca2df37 Speed up with disabled output buffering 2025-02-28 15:37:18 +01:00
Jakub Vrana
315ffc9d8b CSV import: Don't unquote " in unquoted values 2025-02-28 14:40:31 +01:00
Denitz
530b3dd1e5 Add Reset button for tables-filter plugin 2025-02-28 13:52:32 +01:00
Jakub Vrana
980c22fe8d MS SQL: Don't insert identity without IDENTITY_INSERT 2025-02-27 09:42:33 +01:00
Jakub Vrana
26d1e51916 PostgreSQL: Display ENUM types 2025-02-27 09:41:31 +01:00
Jakub Vrana
6d889b9f99 Add test for check constraints 2025-02-27 08:26:05 +01:00
Jakub Vrana
7e4ee77cc0 Fix Create table test 2025-02-27 08:10:44 +01:00
Jakub Vrana
742fd7dcb6 Remove <datalist> from tests 2025-02-27 08:09:45 +01:00
Jakub Vrana
d23a0eb77e PostgreSQL: Export ENUM types (bug #587) 2025-02-26 23:55:17 +01:00
Jakub Vrana
5eac6a44bd PostgreSQL: Link enum doc 2025-02-26 23:38:07 +01:00
Jakub Vrana
db300bc38b MS SQL: Specify columns in CSV import 2025-02-26 22:49:22 +01:00
Jakub Vrana
48a680658c MS SQL: Do not update primary key in CSV import 2025-02-26 22:47:16 +01:00
Jakub Vrana
70f9ff75fc MS SQL: Fix CSV import (bug #859) 2025-02-26 22:40:28 +01:00
Jakub Vrana
81340ff7e5 MS SQL: Compute arrays in insertUpdate only once 2025-02-26 22:35:00 +01:00
Jakub Vrana
89b097c699 Don't hide import if there was an error 2025-02-26 22:28:01 +01:00
Jakub Vrana
e075f4bd8b MS SQL: Import all CSV rows with one command 2025-02-26 22:27:43 +01:00
Jakub Vrana
e8fa48a257 MS SQL: Set identity_insert in CSV import 2025-02-26 22:11:41 +01:00
Takashi SHIRAI
0ed3c5cb19 Fix insertUpdate for mssql
Signed-off-by: Takashi SHIRAI <shirai@nintendo.co.jp>
2025-02-26 22:04:58 +01:00
Jakub Vrana
2f237dfa04 MS SQL export: Create foreign keys after all tables 2025-02-26 21:39:45 +01:00
Jakub Vrana
afdc78a07b PostgreSQL: Sort PRIMARY and UNIQUE indexes first 2025-02-26 21:28:02 +01:00
Jakub Vrana
3dc87c1811 PostgreSQL: Do not alter indexes with expressions 2025-02-26 21:24:47 +01:00
Jakub Vrana
de7bb79132 Remove empty string 2025-02-26 20:01:56 +01:00
Jakub Vrana
f81658ecfe PostgreSQL: Add missing CHECK in export 2025-02-26 19:56:16 +01:00
Jakub Vrana
a603de853d PostgreSQL: Move primary key in export back to table 2025-02-26 19:55:49 +01:00
Jakub Vrana
2998db57d4 PostgreSQL: Print errors in export 2025-02-26 19:37:18 +01:00
Jakub Vrana
9aaa429528 PostgreSQL: Fix export of indexes with expressions (bug #768) 2025-02-26 19:27:19 +01:00
Jakub Vrana
ba70be12a4 PostgreSQL: Fix help link to pg_catalog views 2025-02-26 19:21:13 +01:00
Jakub Vrana
4b47326ffa Use use_sql 2025-02-26 18:47:25 +01:00
Jakub Vrana
848cd482e2 MS SQL: Add support for PDO_SQLSRV extension 2025-02-26 18:08:18 +01:00
Takashi SHIRAI
15cd83fc39 Add seek() to Min_PDOStatement for mssql.
Signed-off-by: Takashi SHIRAI <shirai@nintendo.co.jp>
2025-02-26 17:43:35 +01:00
Jakub Vrana
4de6e47c0a Use \W in friendly_url() 2025-02-26 16:48:02 +01:00
Jakub Vrana
45f24a8f62 Delete unused functions 2025-02-26 16:48:02 +01:00
Jakub Vrana
cf835515b1 Support compiling Elastic driver 2025-02-26 16:48:02 +01:00
Jakub Vrana
c38b967fc4 Foreign keys: Switch schema back after getting the tables 2025-02-26 16:48:02 +01:00
Jakub Vrana
efb1eb9d6b MS SQL: Remove support for MSSQL extension 2025-02-26 16:48:02 +01:00
Jakub Vrana
ce1031e017 MS SQL: Split altering foreign key to two commands 2025-02-26 16:48:02 +01:00
Jakub Vrana
d54be5ac2e MS SQL: Display foreign keys ON UPDATE and ON DELETE 2025-02-26 16:47:55 +01:00
Jakub Vrana
76cc7c6614 MS SQL: Set identity_insert in export 2025-02-26 16:47:24 +01:00
Jakub Vrana
54dd702763 Fix bug number 2025-02-26 16:47:24 +01:00
Jakub Vrana
dfd26d0704 MS SQL: Support export 2025-02-26 16:47:18 +01:00
Jakub Vrana
0f8460b5e8 PostgreSQL: Use function for exporting constraints 2025-02-26 12:35:25 +01:00
Jakub Vrana
09883aa2f5 SQLite: Remove support for SQLite version 2 2025-02-26 12:20:37 +01:00
Jakub Vrana
e3a2b1b57a SQLite: Support CHECK constraint 2025-02-26 12:20:37 +01:00
Jakub Vrana
a28d95a023 SQLite: Constraint getting view by name to views only 2025-02-26 12:20:37 +01:00
Jakub Vrana
ab025e74a3 SQLite: Display all rows of variable values 2025-02-26 12:20:37 +01:00
Jakub Vrana
8077ef41c1 SQLite: Add command Check tables 2025-02-26 12:20:36 +01:00
Jakub Vrana
9d8864a6c7 Compile: Fix removing single driver login form field 2025-02-26 12:20:36 +01:00
Jakub Vrana
e107ef52d5 Move \n to loginFormField 2025-02-26 12:20:36 +01:00
Jakub Vrana
57ec1f924d Allow compiling driver from plugins 2025-02-26 12:20:36 +01:00
Jakub Vrana
491b481b7f Use __DIR__ 2025-02-26 12:20:36 +01:00
Jakub Vrana
e327d31a08 Hide SQL export if driver doesn't support it 2025-02-26 12:20:34 +01:00
Denitz
708a4e9494 Update table-structure.php 2025-02-25 16:44:25 +01:00
Jakub Vrana
c55ad679ac Use Default setup for CodeQL analysis 2025-02-25 16:41:08 +01:00
Jakub Vrana
dccbdfde97 MongoDB: Remove support for deprecated extension mongo 2025-02-25 15:59:04 +01:00
Jakub Vrana
09091c0dac Develop 2025-02-25 07:32:48 +01:00
Jakub Vrana
bb22a965b2 Release 4.17.1 2025-02-25 07:31:42 +01:00
Jakub Vrana
4f0da70733 Move is_c_style_escapes to Min_Driver 2025-02-25 07:26:08 +01:00
Jakub Vrana
a1235f68ff SQLite: Disable backslash escapes 2025-02-25 07:15:57 +01:00
Jakub Vrana
0138f3b0a5 Oracle: Fix foreign key doc link 2025-02-25 07:09:10 +01:00
Jakub Vrana
192ae38d57 MS SQL: Link doc with current version 2025-02-25 06:58:10 +01:00
Jakub Vrana
620e147b8c Check: Add doc link 2025-02-25 06:54:07 +01:00
Jakub Vrana
644cde4855 MS SQL: Update doc_links 2025-02-25 06:52:27 +01:00
Jakub Vrana
c15576bbf8 Use get_rows() 2025-02-25 06:36:32 +01:00
Jakub Vrana
0d8028ddc5 Compile: Do not warn about functions without declared support 2025-02-25 06:30:22 +01:00
Jakub Vrana
242f5a1ed8 MySQL: Fix typo in the date type (regression from 4.17.0) 2025-02-25 05:41:41 +01:00
Jakub Vrana
d12ea17b17 Remove bogus comment 2025-02-25 05:41:12 +01:00
Jakub Vrana
a7365a50b1 Remove border-collapse: separate in designs after removing cellspacing 2025-02-24 16:41:35 +01:00
Jakub Vrana
b5beffb37c Develop 2025-02-24 12:21:15 +01:00
168 changed files with 3876 additions and 3162 deletions

View File

@@ -7,7 +7,7 @@ end_of_line = lf
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
[*.{php,css,js}] [*.{php,css,js,xml}]
indent_style = tab indent_style = tab
[*.json] [*.json]

View File

@@ -1,67 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '20 16 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

View File

@@ -1,5 +1,7 @@
<?php <?php
$PROCEDURE = ($_GET["name"] ? $_GET["name"] : $_GET["call"]); namespace Adminer;
$PROCEDURE = ($_GET["name"] ?: $_GET["call"]);
page_header(lang('Call') . ": " . h($PROCEDURE), $error); page_header(lang('Call') . ": " . h($PROCEDURE), $error);
$routine = routine($_GET["call"], (isset($_GET["callf"]) ? "FUNCTION" : "PROCEDURE")); $routine = routine($_GET["call"], (isset($_GET["callf"]) ? "FUNCTION" : "PROCEDURE"));
@@ -96,14 +98,17 @@ function pre_tr($s) {
} }
$table = '(\+--[-+]+\+\n)'; $table = '(\+--[-+]+\+\n)';
$row = '(\| .* \|\n)'; $row = '(\| .* \|\n)';
echo echo preg_replace_callback(
preg_replace_callback("~^$table?$row$table?($row*)$table?~m", function ($match) { "~^$table?$row$table?($row*)$table?~m",
function ($match) {
$first_row = pre_tr($match[2]); $first_row = pre_tr($match[2]);
return "<table>\n" . ($match[1] ? "<thead>$first_row</thead>\n" : $first_row) . pre_tr($match[4]) . "\n</table>"; return "<table>\n" . ($match[1] ? "<thead>$first_row</thead>\n" : $first_row) . pre_tr($match[4]) . "\n</table>";
}, },
preg_replace('~(\n( -|mysql)&gt; )(.+)~', "\\1<code class='jush-sql'>\\3</code>", preg_replace(
preg_replace('~(.+)\n---+\n~', "<b>\\1</b>\n", '~(\n( -|mysql)&gt; )(.+)~',
h($routine['comment']) "\\1<code class='jush-sql'>\\3</code>",
))); preg_replace('~(.+)\n---+\n~', "<b>\\1</b>\n", h($routine['comment']))
)
);
?> ?>
</pre> </pre>

View File

@@ -1,12 +1,18 @@
<?php <?php
namespace Adminer;
$TABLE = $_GET["check"]; $TABLE = $_GET["check"];
$name = $_GET["name"]; $name = $_GET["name"];
$row = $_POST; $row = $_POST;
if ($row && !$error) { if ($row && !$error) {
$result = ($name == "" || queries("ALTER TABLE " . table($TABLE) . " DROP CONSTRAINT " . idf_escape($name))); if (JUSH == "sqlite") {
if (!$row["drop"]) { $result = recreate_table($TABLE, $TABLE, array(), array(), array(), 0, array(), $name, ($row["drop"] ? "" : $row["clause"]));
$result = queries("ALTER TABLE " . table($TABLE) . " ADD" . ($row["name"] != "" ? " CONSTRAINT " . idf_escape($row["name"]) . "" : "") . " CHECK ($row[clause])"); //! SQL injection } else {
$result = ($name == "" || queries("ALTER TABLE " . table($TABLE) . " DROP CONSTRAINT " . idf_escape($name)));
if (!$row["drop"]) {
$result = queries("ALTER TABLE " . table($TABLE) . " ADD" . ($row["name"] != "" ? " CONSTRAINT " . idf_escape($row["name"]) : "") . " CHECK ($row[clause])"); //! SQL injection
}
} }
queries_redirect( queries_redirect(
ME . "table=" . urlencode($TABLE), ME . "table=" . urlencode($TABLE),
@@ -18,18 +24,28 @@ if ($row && !$error) {
page_header(($name != "" ? lang('Alter check') . ": " . h($name) : lang('Create check')), $error, array("table" => $TABLE)); page_header(($name != "" ? lang('Alter check') . ": " . h($name) : lang('Create check')), $error, array("table" => $TABLE));
if (!$row) { if (!$row) {
$checks = check_constraints($TABLE); $checks = $driver->checkConstraints($TABLE);
$row = array("name" => $name, "clause" => $checks[$name]); $row = array("name" => $name, "clause" => $checks[$name]);
} }
?> ?>
<form action="" method="post"> <form action="" method="post">
<p><?php echo lang('Name'); ?>: <input name="name" value="<?php echo h($row["name"]); ?>" data-maxlength="64" autocapitalize="off"><?php echo doc_link(array( <p><?php
'sql' => 'create-table-check-constraints.html', if (JUSH != "sqlite") {
'mariadb' => 'constraint/', echo lang('Name') . ': <input name="name" value="' . h($row["name"]) . '" data-maxlength="64" autocapitalize="off"> ';
)); ?> }
echo doc_link(array(
'sql' => "create-table-check-constraints.html",
'mariadb' => "constraint/",
'pgsql' => "ddl-constraints.html#DDL-CONSTRAINTS-CHECK-CONSTRAINTS",
'mssql' => "relational-databases/tables/create-check-constraints",
'sqlite' => "lang_createtable.html#check_constraints",
), "?");
?>
<p><?php textarea("clause", $row["clause"]); ?> <p><?php textarea("clause", $row["clause"]); ?>
<p><input type="submit" value="<?php echo lang('Save'); ?>"> <p><input type="submit" value="<?php echo lang('Save'); ?>">
<?php if ($name != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $name)); ?><?php } ?> <?php if ($name != "") { ?>
<input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $name)); ?>
<?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>"> <input type="hidden" name="token" value="<?php echo $token; ?>">
</form> </form>

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$TABLE = $_GET["create"]; $TABLE = $_GET["create"];
$partition_by = array(); $partition_by = array();
foreach (array('HASH', 'LINEAR HASH', 'KEY', 'LINEAR KEY', 'RANGE', 'LIST') as $key) { foreach (array('HASH', 'LINEAR HASH', 'KEY', 'LINEAR KEY', 'RANGE', 'LIST') as $key) {
@@ -46,7 +48,7 @@ if ($_POST && !process_fields($row["fields"]) && !$error) {
$foreign_key = $foreign_keys[$field["type"]]; $foreign_key = $foreign_keys[$field["type"]];
$type_field = ($foreign_key !== null ? $referencable_primary[$foreign_key] : $field); //! can collide with user defined type $type_field = ($foreign_key !== null ? $referencable_primary[$foreign_key] : $field); //! can collide with user defined type
if ($field["field"] != "") { if ($field["field"] != "") {
if (!$field["has_default"]) { if (!$field["generated"]) {
$field["default"] = null; $field["default"] = null;
} }
$process_field = process_field($field, $type_field); $process_field = process_field($field, $type_field);
@@ -58,7 +60,7 @@ if ($_POST && !process_fields($row["fields"]) && !$error) {
} }
} }
if ($foreign_key !== null) { if ($foreign_key !== null) {
$foreign[idf_escape($field["field"])] = ($TABLE != "" && $jush != "sqlite" ? "ADD" : " ") . format_foreign_key(array( $foreign[idf_escape($field["field"])] = ($TABLE != "" && JUSH != "sqlite" ? "ADD" : " ") . format_foreign_key(array(
'table' => $foreign_keys[$field["type"]], 'table' => $foreign_keys[$field["type"]],
'source' => array($field["field"]), 'source' => array($field["field"]),
'target' => array($type_field["field"]), 'target' => array($type_field["field"]),
@@ -124,7 +126,7 @@ if ($_POST && !process_fields($row["fields"]) && !$error) {
queries_redirect(ME . (support("table") ? "table=" : "select=") . urlencode($name), $message, alter_table( queries_redirect(ME . (support("table") ? "table=" : "select=") . urlencode($name), $message, alter_table(
$TABLE, $TABLE,
$name, $name,
($jush == "sqlite" && ($use_all_fields || $foreign) ? $all_fields : $fields), (JUSH == "sqlite" && ($use_all_fields || $foreign) ? $all_fields : $fields),
$foreign, $foreign,
($row["Comment"] != $table_status["Comment"] ? $row["Comment"] : null), ($row["Comment"] != $table_status["Comment"] ? $row["Comment"] : null),
($row["Engine"] && $row["Engine"] != $table_status["Engine"] ? $row["Engine"] : ""), ($row["Engine"] && $row["Engine"] != $table_status["Engine"] ? $row["Engine"] : ""),
@@ -138,6 +140,7 @@ if ($_POST && !process_fields($row["fields"]) && !$error) {
page_header(($TABLE != "" ? lang('Alter table') : lang('Create table')), $error, array("table" => $TABLE), h($TABLE)); page_header(($TABLE != "" ? lang('Alter table') : lang('Create table')), $error, array("table" => $TABLE), h($TABLE));
if (!$_POST) { if (!$_POST) {
$types = $driver->types();
$row = array( $row = array(
"Engine" => $_COOKIE["adminer_engine"], "Engine" => $_COOKIE["adminer_engine"],
"fields" => array(array("field" => "", "type" => (isset($types["int"]) ? "int" : (isset($types["integer"]) ? "integer" : "")), "on_update" => "")), "fields" => array(array("field" => "", "type" => (isset($types["int"]) ? "int" : (isset($types["integer"]) ? "integer" : "")), "on_update" => "")),
@@ -152,7 +155,7 @@ if (!$_POST) {
$row["Auto_increment"] = ""; $row["Auto_increment"] = "";
} }
foreach ($orig_fields as $field) { foreach ($orig_fields as $field) {
$field["has_default"] = isset($field["default"]); $field["generated"] = $field["generated"] ?: (isset($field["default"]) ? "DEFAULT" : "");
$row["fields"][] = $field; $row["fields"][] = $field;
} }
@@ -180,7 +183,7 @@ foreach ($engines as $engine) {
<?php if (support("columns") || $TABLE == "") { ?> <?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 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 ? "<select name='Engine'>" . optionlist(array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . "</select>" . on_help("getTarget(event).value", 1) . script("qsl('select').onchange = helpClose;") : ""); ?> <?php echo ($engines ? "<select name='Engine'>" . optionlist(array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) . "</select>" . on_help("getTarget(event).value", 1) . script("qsl('select').onchange = helpClose;") : ""); ?>
<?php echo ($collations && !preg_match("~sqlite|mssql~", $jush) ? html_select("Collation", array("" => "(" . lang('collation') . ")") + $collations, $row["Collation"]) : ""); ?> <?php echo ($collations && !preg_match("~sqlite|mssql~", JUSH) ? html_select("Collation", array("" => "(" . lang('collation') . ")") + $collations, $row["Collation"]) : ""); ?>
<input type="submit" value="<?php echo lang('Save'); ?>"> <input type="submit" value="<?php echo lang('Save'); ?>">
<?php } ?> <?php } ?>
@@ -188,8 +191,8 @@ foreach ($engines as $engine) {
<div class="scrollable"> <div class="scrollable">
<table id="edit-fields" class="nowrap"> <table id="edit-fields" class="nowrap">
<?php <?php
edit_fields($row["fields"], $collations, "TABLE", $foreign_keys); edit_fields($row["fields"], $collations, "TABLE", $foreign_keys);
?> ?>
</table> </table>
<?php echo script("editFields();"); ?> <?php echo script("editFields();"); ?>
</div> </div>
@@ -197,21 +200,23 @@ edit_fields($row["fields"], $collations, "TABLE", $foreign_keys);
<?php echo lang('Auto Increment'); ?>: <input type="number" name="Auto_increment" class="size" value="<?php echo h($row["Auto_increment"]); ?>"> <?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 echo checkbox("defaults", 1, ($_POST ? $_POST["defaults"] : adminer_setting("defaults")), lang('Default values'), "columnShow(this.checked, 5)", "jsonly"); ?>
<?php <?php
$comments = ($_POST ? $_POST["comments"] : adminer_setting("comments")); $comments = ($_POST ? $_POST["comments"] : adminer_setting("comments"));
echo (support("comment") echo (support("comment")
? checkbox("comments", 1, $comments, lang('Comment'), "editingCommentsClick(this, true);", "jsonly") ? checkbox("comments", 1, $comments, lang('Comment'), "editingCommentsClick(this, true);", "jsonly")
. ' ' . (preg_match('~\n~', $row["Comment"]) . ' ' . (preg_match('~\n~', $row["Comment"])
? "<textarea name='Comment' rows='2' cols='20'" . ($comments ? "" : " class='hidden'") . ">" . h($row["Comment"]) . "</textarea>" ? "<textarea name='Comment' rows='2' cols='20'" . ($comments ? "" : " class='hidden'") . ">" . h($row["Comment"]) . "</textarea>"
: '<input name="Comment" value="' . h($row["Comment"]) . '" data-maxlength="' . (min_version(5.5) ? 2048 : 60) . '"' . ($comments ? "" : " class='hidden'") . '>' : '<input name="Comment" value="' . h($row["Comment"]) . '" data-maxlength="' . (min_version(5.5) ? 2048 : 60) . '"' . ($comments ? "" : " class='hidden'") . '>'
) )
: '') : '')
; ;
?> ?>
<p> <p>
<input type="submit" value="<?php echo lang('Save'); ?>"> <input type="submit" value="<?php echo lang('Save'); ?>">
<?php } ?> <?php } ?>
<?php if ($TABLE != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $TABLE)); ?><?php } ?> <?php if ($TABLE != "") { ?>
<input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $TABLE)); ?>
<?php } ?>
<?php <?php
if (support("partitioning")) { if (support("partitioning")) {
$partition_table = preg_match('~RANGE|LIST~', $row["partition_by"]); $partition_table = preg_match('~RANGE|LIST~', $row["partition_by"]);
@@ -224,13 +229,13 @@ if (support("partitioning")) {
<table id="partition-table"<?php echo ($partition_table ? "" : " class='hidden'"); ?>> <table id="partition-table"<?php echo ($partition_table ? "" : " class='hidden'"); ?>>
<thead><tr><th><?php echo lang('Partition name'); ?><th><?php echo lang('Values'); ?></thead> <thead><tr><th><?php echo lang('Partition name'); ?><th><?php echo lang('Values'); ?></thead>
<?php <?php
foreach ($row["partition_names"] as $key => $val) { foreach ($row["partition_names"] as $key => $val) {
echo '<tr>'; echo '<tr>';
echo '<td><input name="partition_names[]" value="' . h($val) . '" autocapitalize="off">'; echo '<td><input name="partition_names[]" value="' . h($val) . '" autocapitalize="off">';
echo ($key == count($row["partition_names"]) - 1 ? script("qsl('input').oninput = partitionNameChange;") : ''); echo ($key == count($row["partition_names"]) - 1 ? script("qsl('input').oninput = partitionNameChange;") : '');
echo '<td><input name="partition_values[]" value="' . h($row["partition_values"][$key]) . '">'; echo '<td><input name="partition_values[]" value="' . h($row["partition_values"][$key]) . '">';
} }
?> ?>
</table> </table>
</div></fieldset> </div></fieldset>
<?php <?php

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$row = $_POST; $row = $_POST;
if ($_POST && !$error && !isset($_POST["add_x"])) { // add is an image and PHP changes add.x to add_x if ($_POST && !$error && !isset($_POST["add_x"])) { // add is an image and PHP changes add.x to add_x
@@ -44,7 +46,7 @@ if ($_POST) {
$name = $row["name"]; $name = $row["name"];
} elseif (DB != "") { } elseif (DB != "") {
$row["collation"] = db_collation(DB, $collations); $row["collation"] = db_collation(DB, $collations);
} elseif ($jush == "sql") { } elseif (JUSH == "sql") {
// propose database name with limited privileges // propose database name with limited privileges
foreach (get_vals("SHOW GRANTS") as $grant) { foreach (get_vals("SHOW GRANTS") as $grant) {
if (preg_match('~ ON (`(([^\\\\`]|``|\\\\.)*)%`\.\*)?~', $grant, $match) && $match[1]) { if (preg_match('~ ON (`(([^\\\\`]|``|\\\\.)*)%`\.\*)?~', $grant, $match) && $match[1]) {
@@ -64,7 +66,7 @@ echo ($_POST["add_x"] || strpos($name, "\n")
) . "\n" . ($collations ? html_select("collation", array("" => "(" . lang('collation') . ")") + $collations, $row["collation"]) . doc_link(array( ) . "\n" . ($collations ? html_select("collation", array("" => "(" . lang('collation') . ")") + $collations, $row["collation"]) . doc_link(array(
'sql' => "charset-charsets.html", 'sql' => "charset-charsets.html",
'mariadb' => "supported-character-sets-and-collations/", 'mariadb' => "supported-character-sets-and-collations/",
'mssql' => "ms187963.aspx", 'mssql' => "relational-databases/system-functions/sys-fn-helpcollations-transact-sql",
)) : ""); )) : "");
?> ?>
<input type="submit" value="<?php echo lang('Save'); ?>"> <input type="submit" value="<?php echo lang('Save'); ?>">

View File

@@ -1,10 +1,12 @@
<?php <?php
namespace Adminer;
$tables_views = array_merge((array) $_POST["tables"], (array) $_POST["views"]); $tables_views = array_merge((array) $_POST["tables"], (array) $_POST["views"]);
if ($tables_views && !$error && !$_POST["search"]) { if ($tables_views && !$error && !$_POST["search"]) {
$result = true; $result = true;
$message = ""; $message = "";
if ($jush == "sql" && $_POST["tables"] && count($_POST["tables"]) > 1 && ($_POST["drop"] || $_POST["truncate"] || $_POST["copy"])) { if (JUSH == "sql" && $_POST["tables"] && count($_POST["tables"]) > 1 && ($_POST["drop"] || $_POST["truncate"] || $_POST["copy"])) {
queries("SET foreign_key_checks = 0"); // allows to truncate or drop several tables at once queries("SET foreign_key_checks = 0"); // allows to truncate or drop several tables at once
} }
@@ -27,15 +29,21 @@ if ($tables_views && !$error && !$_POST["search"]) {
$result = drop_tables($_POST["tables"]); $result = drop_tables($_POST["tables"]);
} }
$message = lang('Tables have been dropped.'); $message = lang('Tables have been dropped.');
} elseif ($jush != "sql") { } elseif (JUSH == "sqlite" && $_POST["check"]) {
$result = ($jush == "sqlite" foreach ((array) $_POST["tables"] as $table) {
foreach (get_rows("PRAGMA integrity_check(" . q($table) . ")") as $row) {
$message .= "<b>" . h($table) . "</b>: " . h($row["integrity_check"]) . "<br>";
}
}
} elseif (JUSH != "sql") {
$result = (JUSH == "sqlite"
? queries("VACUUM") ? queries("VACUUM")
: apply_queries("VACUUM" . ($_POST["optimize"] ? "" : " ANALYZE"), $_POST["tables"]) : apply_queries("VACUUM" . ($_POST["optimize"] ? "" : " ANALYZE"), $_POST["tables"])
); );
$message = lang('Tables have been optimized.'); $message = lang('Tables have been optimized.');
} elseif (!$_POST["tables"]) { } elseif (!$_POST["tables"]) {
$message = lang('No tables.'); $message = lang('No tables.');
} elseif ($result = queries(($_POST["optimize"] ? "OPTIMIZE" : ($_POST["check"] ? "CHECK" : ($_POST["repair"] ? "REPAIR" : "ANALYZE"))) . " TABLE " . implode(", ", array_map('idf_escape', $_POST["tables"])))) { } elseif ($result = queries(($_POST["optimize"] ? "OPTIMIZE" : ($_POST["check"] ? "CHECK" : ($_POST["repair"] ? "REPAIR" : "ANALYZE"))) . " TABLE " . implode(", ", array_map('Adminer\idf_escape', $_POST["tables"])))) {
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$message .= "<b>" . h($row["Table"]) . "</b>: " . h($row["Msg_text"]) . "<br>"; $message .= "<b>" . h($row["Table"]) . "</b>: " . h($row["Msg_text"]) . "<br>";
} }
@@ -91,15 +99,17 @@ if ($adminer->homepage()) {
echo '<td colspan="6"><a href="' . h(ME) . "view=" . urlencode($name) . '" title="' . lang('Alter view') . '">' . (preg_match('~materialized~i', $type) ? lang('Materialized view') : lang('View')) . '</a>'; echo '<td colspan="6"><a href="' . h(ME) . "view=" . urlencode($name) . '" title="' . lang('Alter view') . '">' . (preg_match('~materialized~i', $type) ? lang('Materialized view') : lang('View')) . '</a>';
echo '<td align="right"><a href="' . h(ME) . "select=" . urlencode($name) . '" title="' . lang('Select data') . '">?</a>'; echo '<td align="right"><a href="' . h(ME) . "select=" . urlencode($name) . '" title="' . lang('Select data') . '">?</a>';
} else { } else {
foreach (array( foreach (
"Engine" => array(), array(
"Collation" => array(), "Engine" => array(),
"Data_length" => array("create", lang('Alter table')), "Collation" => array(),
"Index_length" => array("indexes", lang('Alter indexes')), "Data_length" => array("create", lang('Alter table')),
"Data_free" => array("edit", lang('New item')), "Index_length" => array("indexes", lang('Alter indexes')),
"Auto_increment" => array("auto_increment=1&create", lang('Alter table')), "Data_free" => array("edit", lang('New item')),
"Rows" => array("select", lang('Select data')), "Auto_increment" => array("auto_increment=1&create", lang('Alter table')),
) as $key => $link) { "Rows" => array("select", lang('Select data')),
) as $key => $link
) {
$id = " id='$key-" . h($name) . "'"; $id = " id='$key-" . h($name) . "'";
echo ($link ? "<td align='right'>" . (support("table") || $key == "Rows" || (support("indexes") && $key != "Data_length") echo ($link ? "<td align='right'>" . (support("table") || $key == "Rows" || (support("indexes") && $key != "Data_length")
? "<a href='" . h(ME . "$link[0]=") . urlencode($name) . "'$id title='$link[1]'>?</a>" ? "<a href='" . h(ME . "$link[0]=") . urlencode($name) . "'$id title='$link[1]'>?</a>"
@@ -113,7 +123,7 @@ if ($adminer->homepage()) {
} }
echo "<tr><td><th>" . lang('%d in total', count($tables_list)); echo "<tr><td><th>" . lang('%d in total', count($tables_list));
echo "<td>" . h($jush == "sql" ? $connection->result("SELECT @@default_storage_engine") : ""); echo "<td>" . h(JUSH == "sql" ? $connection->result("SELECT @@default_storage_engine") : "");
echo "<td>" . h(db_collation(DB, collations())); echo "<td>" . h(db_collation(DB, collations()));
foreach (array("Data_length", "Index_length", "Data_free") as $key) { foreach (array("Data_length", "Index_length", "Data_free") as $key) {
echo "<td align='right' id='sum-$key'>"; echo "<td align='right' id='sum-$key'>";
@@ -125,18 +135,19 @@ if ($adminer->homepage()) {
if (!information_schema(DB)) { if (!information_schema(DB)) {
echo "<div class='footer'><div>\n"; echo "<div class='footer'><div>\n";
$vacuum = "<input type='submit' value='" . lang('Vacuum') . "'> " . on_help("'VACUUM'"); $vacuum = "<input type='submit' value='" . lang('Vacuum') . "'> " . on_help("'VACUUM'");
$optimize = "<input type='submit' name='optimize' value='" . lang('Optimize') . "'> " . on_help($jush == "sql" ? "'OPTIMIZE TABLE'" : "'VACUUM OPTIMIZE'"); $optimize = "<input type='submit' name='optimize' value='" . lang('Optimize') . "'> " . on_help(JUSH == "sql" ? "'OPTIMIZE TABLE'" : "'VACUUM OPTIMIZE'");
echo "<fieldset><legend>" . lang('Selected') . " <span id='selected'></span></legend><div>" echo "<fieldset><legend>" . lang('Selected') . " <span id='selected'></span></legend><div>"
. ($jush == "sqlite" ? $vacuum . (JUSH == "sqlite" ? $vacuum . "<input type='submit' name='check' value='" . lang('Check') . "'> " . on_help("'PRAGMA integrity_check'")
: ($jush == "pgsql" ? $vacuum . $optimize : (JUSH == "pgsql" ? $vacuum . $optimize
: ($jush == "sql" ? "<input type='submit' value='" . lang('Analyze') . "'> " . on_help("'ANALYZE TABLE'") . $optimize : (JUSH == "sql" ? "<input type='submit' value='" . lang('Analyze') . "'> " . on_help("'ANALYZE TABLE'")
. $optimize
. "<input type='submit' name='check' value='" . lang('Check') . "'> " . on_help("'CHECK TABLE'") . "<input type='submit' name='check' value='" . lang('Check') . "'> " . on_help("'CHECK TABLE'")
. "<input type='submit' name='repair' value='" . lang('Repair') . "'> " . on_help("'REPAIR TABLE'") . "<input type='submit' name='repair' value='" . lang('Repair') . "'> " . on_help("'REPAIR TABLE'")
: ""))) : "")))
. "<input type='submit' name='truncate' value='" . lang('Truncate') . "'> " . on_help($jush == "sqlite" ? "'DELETE'" : "'TRUNCATE" . ($jush == "pgsql" ? "'" : " TABLE'")) . confirm() . "<input type='submit' name='truncate' value='" . lang('Truncate') . "'> " . on_help(JUSH == "sqlite" ? "'DELETE'" : "'TRUNCATE" . (JUSH == "pgsql" ? "'" : " TABLE'")) . confirm()
. "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . on_help("'DROP TABLE'") . confirm() . "\n"; . "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . on_help("'DROP TABLE'") . confirm() . "\n";
$databases = (support("scheme") ? $adminer->schemas() : $adminer->databases()); $databases = (support("scheme") ? $adminer->schemas() : $adminer->databases());
if (count($databases) != 1 && $jush != "sqlite") { if (count($databases) != 1 && JUSH != "sqlite") {
$db = (isset($_POST["target"]) ? $_POST["target"] : (support("scheme") ? $_GET["ns"] : DB)); $db = (isset($_POST["target"]) ? $_POST["target"] : (support("scheme") ? $_GET["ns"] : DB));
echo "<p>" . lang('Move to other database') . ": "; echo "<p>" . lang('Move to other database') . ": ";
echo ($databases ? html_select("target", $databases, $db) : '<input name="target" value="' . h($db) . '" autocapitalize="off">'); echo ($databases ? html_select("target", $databases, $db) : '<input name="target" value="' . h($db) . '" autocapitalize="off">');

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$TABLE = $_GET["download"]; $TABLE = $_GET["download"];
$fields = fields($TABLE); $fields = fields($TABLE);
header("Content-Type: application/octet-stream"); header("Content-Type: application/octet-stream");

View File

@@ -1,229 +1,26 @@
<?php <?php
namespace Adminer;
$drivers["mongo"] = "MongoDB (alpha)"; $drivers["mongo"] = "MongoDB (alpha)";
if (isset($_GET["mongo"])) { if (isset($_GET["mongo"])) {
define("DRIVER", "mongo"); define('Adminer\DRIVER', "mongo");
if (class_exists('MongoDB')) { if (class_exists('MongoDB\Driver\Manager')) {
class Min_DB { class Db {
var $extension = "Mongo", $server_info = MongoClient::VERSION, $error, $last_id, $_link, $_db;
function connect($uri, $options) {
try {
$this->_link = new MongoClient($uri, $options);
if ($options["password"] != "") {
$options["password"] = "";
try {
new MongoClient($uri, $options);
$this->error = lang('Database does not support password.');
} catch (Exception $e) {
// this is what we want
}
}
} catch (Exception $e) {
$this->error = $e->getMessage();
}
}
function query($query) {
return false;
}
function select_db($database) {
try {
$this->_db = $this->_link->selectDB($database);
return true;
} catch (Exception $ex) {
$this->error = $ex->getMessage();
return false;
}
}
function quote($string) {
return $string;
}
}
class Min_Result {
var $num_rows, $_rows = array(), $_offset = 0, $_charset = array();
function __construct($result) {
foreach ($result as $item) {
$row = array();
foreach ($item as $key => $val) {
if (is_a($val, 'MongoBinData')) {
$this->_charset[$key] = 63;
}
$row[$key] =
(is_a($val, 'MongoId') ? "ObjectId(\"$val\")" :
(is_a($val, 'MongoDate') ? gmdate("Y-m-d H:i:s", $val->sec) . " GMT" :
(is_a($val, 'MongoBinData') ? $val->bin : //! allow downloading
(is_a($val, 'MongoRegex') ? "$val" :
(is_object($val) ? get_class($val) : // MongoMinKey, MongoMaxKey
$val
)))));
}
$this->_rows[] = $row;
foreach ($row as $key => $val) {
if (!isset($this->_rows[0][$key])) {
$this->_rows[0][$key] = null;
}
}
}
$this->num_rows = count($this->_rows);
}
function fetch_assoc() {
$row = current($this->_rows);
if (!$row) {
return $row;
}
$return = array();
foreach ($this->_rows[0] as $key => $val) {
$return[$key] = $row[$key];
}
next($this->_rows);
return $return;
}
function fetch_row() {
$return = $this->fetch_assoc();
if (!$return) {
return $return;
}
return array_values($return);
}
function fetch_field() {
$keys = array_keys($this->_rows[0]);
$name = $keys[$this->_offset++];
return (object) array(
'name' => $name,
'charsetnr' => $this->_charset[$name],
);
}
}
class Min_Driver extends Min_SQL {
public $primary = "_id";
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
$select = ($select == array("*")
? array()
: array_fill_keys($select, true)
);
$sort = array();
foreach ($order as $val) {
$val = preg_replace('~ DESC$~', '', $val, 1, $count);
$sort[$val] = ($count ? -1 : 1);
}
return new Min_Result($this->_conn->_db->selectCollection($table)
->find(array(), $select)
->sort($sort)
->limit($limit != "" ? +$limit : 0)
->skip($page * $limit)
);
}
function insert($table, $set) {
try {
$return = $this->_conn->_db->selectCollection($table)->insert($set);
$this->_conn->errno = $return['code'];
$this->_conn->error = $return['err'];
$this->_conn->last_id = $set['_id'];
return !$return['err'];
} catch (Exception $ex) {
$this->_conn->error = $ex->getMessage();
return false;
}
}
}
function get_databases($flush) {
global $connection;
$return = array();
$dbs = $connection->_link->listDBs();
foreach ($dbs['databases'] as $db) {
$return[] = $db['name'];
}
return $return;
}
function count_tables($databases) {
global $connection;
$return = array();
foreach ($databases as $db) {
$return[$db] = count($connection->_link->selectDB($db)->getCollectionNames(true));
}
return $return;
}
function tables_list() {
global $connection;
return array_fill_keys($connection->_db->getCollectionNames(true), 'table');
}
function drop_databases($databases) {
global $connection;
foreach ($databases as $db) {
$response = $connection->_link->selectDB($db)->drop();
if (!$response['ok']) {
return false;
}
}
return true;
}
function indexes($table, $connection2 = null) {
global $connection;
$return = array();
foreach ($connection->_db->selectCollection($table)->getIndexInfo() as $index) {
$descs = array();
foreach ($index["key"] as $column => $type) {
$descs[] = ($type == -1 ? '1' : null);
}
$return[$index["name"]] = array(
"type" => ($index["name"] == "_id_" ? "PRIMARY" : ($index["unique"] ? "UNIQUE" : "INDEX")),
"columns" => array_keys($index["key"]),
"lengths" => array(),
"descs" => $descs,
);
}
return $return;
}
function fields($table) {
return fields_from_edit();
}
function found_rows($table_status, $where) {
global $connection;
//! don't call count_rows()
return $connection->_db->selectCollection($_GET["select"])->count($where);
}
$operators = array("=");
} elseif (class_exists('MongoDB\Driver\Manager')) {
class Min_DB {
var $extension = "MongoDB", $server_info = MONGODB_VERSION, $affected_rows, $error, $last_id; var $extension = "MongoDB", $server_info = MONGODB_VERSION, $affected_rows, $error, $last_id;
/** @var MongoDB\Driver\Manager */ /** @var MongoDB\Driver\Manager */
var $_link; var $_link;
var $_db, $_db_name; var $_db, $_db_name;
function connect($uri, $options) { function connect($uri, $options) {
$class = 'MongoDB\Driver\Manager'; $this->_link = new \MongoDB\Driver\Manager($uri, $options);
$this->_link = new $class($uri, $options);
$this->executeCommand($options["db"], array('ping' => 1)); $this->executeCommand($options["db"], array('ping' => 1));
} }
function executeCommand($db, $command) { function executeCommand($db, $command) {
$class = 'MongoDB\Driver\Command';
try { try {
return $this->_link->executeCommand($db, new $class($command)); return $this->_link->executeCommand($db, new \MongoDB\Driver\Command($command));
} catch (Exception $e) { } catch (Exception $e) {
$this->error = $e->getMessage(); $this->error = $e->getMessage();
return array(); return array();
@@ -255,7 +52,7 @@ if (isset($_GET["mongo"])) {
} }
} }
class Min_Result { class Result {
var $num_rows, $_rows = array(), $_offset = 0, $_charset = array(); var $num_rows, $_rows = array(), $_offset = 0, $_charset = array();
function __construct($result) { function __construct($result) {
@@ -313,88 +110,9 @@ if (isset($_GET["mongo"])) {
'charsetnr' => $this->_charset[$name], 'charsetnr' => $this->_charset[$name],
); );
} }
} }
class Min_Driver extends Min_SQL {
public $primary = "_id";
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
global $connection;
$select = ($select == array("*")
? array()
: array_fill_keys($select, 1)
);
if (count($select) && !isset($select['_id'])) {
$select['_id'] = 0;
}
$where = where_to_query($where);
$sort = array();
foreach ($order as $val) {
$val = preg_replace('~ DESC$~', '', $val, 1, $count);
$sort[$val] = ($count ? -1 : 1);
}
if (isset($_GET['limit']) && is_numeric($_GET['limit']) && $_GET['limit'] > 0) {
$limit = $_GET['limit'];
}
$limit = min(200, max(1, (int) $limit));
$skip = $page * $limit;
$class = 'MongoDB\Driver\Query';
try {
return new Min_Result($connection->_link->executeQuery("$connection->_db_name.$table", new $class($where, array('projection' => $select, 'limit' => $limit, 'skip' => $skip, 'sort' => $sort))));
} catch (Exception $e) {
$connection->error = $e->getMessage();
return false;
}
}
function update($table, $set, $queryWhere, $limit = 0, $separator = "\n") {
global $connection;
$db = $connection->_db_name;
$where = sql_query_where_parser($queryWhere);
$class = 'MongoDB\Driver\BulkWrite';
$bulk = new $class(array());
if (isset($set['_id'])) {
unset($set['_id']);
}
$removeFields = array();
foreach ($set as $key => $value) {
if ($value == 'NULL') {
$removeFields[$key] = 1;
unset($set[$key]);
}
}
$update = array('$set' => $set);
if (count($removeFields)) {
$update['$unset'] = $removeFields;
}
$bulk->update($where, $update, array('upsert' => false));
return $connection->executeBulkWrite("$db.$table", $bulk, 'getModifiedCount');
}
function delete($table, $queryWhere, $limit = 0) {
global $connection;
$db = $connection->_db_name;
$where = sql_query_where_parser($queryWhere);
$class = 'MongoDB\Driver\BulkWrite';
$bulk = new $class(array());
$bulk->delete($where, array('limit' => $limit));
return $connection->executeBulkWrite("$db.$table", $bulk, 'getDeletedCount');
}
function insert($table, $set) {
global $connection;
$db = $connection->_db_name;
$class = 'MongoDB\Driver\BulkWrite';
$bulk = new $class(array());
if ($set['_id'] == '') {
unset($set['_id']);
}
$bulk->insert($set);
return $connection->executeBulkWrite("$db.$table", $bulk, 'getInsertedCount');
}
}
function get_databases($flush) { function get_databases($flush) {
global $connection; global $connection;
@@ -517,9 +235,8 @@ if (isset($_GET["mongo"])) {
$val = (float) $val; $val = (float) $val;
$op = $match[1]; $op = $match[1];
} elseif (preg_match('~^\(date\)(.+)~', $op, $match)) { } elseif (preg_match('~^\(date\)(.+)~', $op, $match)) {
$dateTime = new DateTime($val); $dateTime = new \DateTime($val);
$class = 'MongoDB\BSON\UTCDatetime'; $val = new \MongoDB\BSON\UTCDatetime($dateTime->getTimestamp() * 1000);
$val = new $class($dateTime->getTimestamp() * 1000);
$op = $match[1]; $op = $match[1];
} }
switch ($op) { switch ($op) {
@@ -557,8 +274,17 @@ if (isset($_GET["mongo"])) {
} }
return $data; return $data;
} }
}
$operators = array(
class Driver extends SqlDriver {
static $possibleDrivers = array("mongodb");
static $jush = "mongo";
var $editFunctions = array(array("json"));
var $operators = array(
"=", "=",
"!=", "!=",
">", ">",
@@ -580,8 +306,78 @@ if (isset($_GET["mongo"])) {
"(date)<=", "(date)<=",
); );
public $primary = "_id";
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
$select = ($select == array("*")
? array()
: array_fill_keys($select, 1)
);
if (count($select) && !isset($select['_id'])) {
$select['_id'] = 0;
}
$where = where_to_query($where);
$sort = array();
foreach ($order as $val) {
$val = preg_replace('~ DESC$~', '', $val, 1, $count);
$sort[$val] = ($count ? -1 : 1);
}
if (isset($_GET['limit']) && is_numeric($_GET['limit']) && $_GET['limit'] > 0) {
$limit = $_GET['limit'];
}
$limit = min(200, max(1, (int) $limit));
$skip = $page * $limit;
try {
return new Result($this->_conn->_link->executeQuery("$connection->_db_name.$table", new \MongoDB\Driver\Query($where, array('projection' => $select, 'limit' => $limit, 'skip' => $skip, 'sort' => $sort))));
} catch (Exception $e) {
$connection->error = $e->getMessage();
return false;
}
}
function update($table, $set, $queryWhere, $limit = 0, $separator = "\n") {
$db = $this->_conn->_db_name;
$where = sql_query_where_parser($queryWhere);
$bulk = new \MongoDB\Driver\BulkWrite(array());
if (isset($set['_id'])) {
unset($set['_id']);
}
$removeFields = array();
foreach ($set as $key => $value) {
if ($value == 'NULL') {
$removeFields[$key] = 1;
unset($set[$key]);
}
}
$update = array('$set' => $set);
if (count($removeFields)) {
$update['$unset'] = $removeFields;
}
$bulk->update($where, $update, array('upsert' => false));
return $this->_conn->executeBulkWrite("$db.$table", $bulk, 'getModifiedCount');
}
function delete($table, $queryWhere, $limit = 0) {
$db = $this->_conn->_db_name;
$where = sql_query_where_parser($queryWhere);
$bulk = new \MongoDB\Driver\BulkWrite(array());
$bulk->delete($where, array('limit' => $limit));
return $this->_conn->executeBulkWrite("$db.$table", $bulk, 'getDeletedCount');
}
function insert($table, $set) {
$db = $this->_conn->_db_name;
$bulk = new \MongoDB\Driver\BulkWrite(array());
if ($set['_id'] == '') {
unset($set['_id']);
}
$bulk->insert($set);
return $this->_conn->executeBulkWrite("$db.$table", $bulk, 'getInsertedCount');
}
} }
function table($idf) { function table($idf) {
return $idf; return $idf;
} }
@@ -627,7 +423,7 @@ if (isset($_GET["mongo"])) {
function connect() { function connect() {
global $adminer; global $adminer;
$connection = new Min_DB; $connection = new Db;
list($server, $username, $password) = $adminer->credentials(); list($server, $username, $password) = $adminer->credentials();
if ($server == "") { if ($server == "") {
@@ -739,16 +535,4 @@ if (isset($_GET["mongo"])) {
} }
return true; return true;
} }
function driver_config() {
global $operators;
return array(
'possible_drivers' => array("mongo", "mongodb"),
'jush' => "mongo",
'operators' => $operators,
'functions' => array(),
'grouping' => array(),
'edit_functions' => array(array("json")),
);
}
} }

View File

@@ -5,12 +5,14 @@
* @author Jakub Vrana * @author Jakub Vrana
*/ */
namespace Adminer;
$drivers["mssql"] = "MS SQL"; $drivers["mssql"] = "MS SQL";
if (isset($_GET["mssql"])) { if (isset($_GET["mssql"])) {
define("DRIVER", "mssql"); define('Adminer\DRIVER', "mssql");
if (extension_loaded("sqlsrv")) { if (extension_loaded("sqlsrv")) {
class Min_DB { class Db {
var $extension = "sqlsrv", $_link, $_result, $server_info, $affected_rows, $errno, $error; var $extension = "sqlsrv", $_link, $_result, $server_info, $affected_rows, $errno, $error;
function _get_error() { function _get_error() {
@@ -52,7 +54,7 @@ if (isset($_GET["mssql"])) {
} }
function select_db($database) { function select_db($database) {
return $this->query("USE " . idf_escape($database)); return $this->query(use_sql($database));
} }
function query($query, $unbuffered = false) { function query($query, $unbuffered = false) {
@@ -83,7 +85,7 @@ if (isset($_GET["mssql"])) {
return false; return false;
} }
if (sqlsrv_field_metadata($result)) { if (sqlsrv_field_metadata($result)) {
return new Min_Result($result); return new Result($result);
} }
$this->affected_rows = sqlsrv_rows_affected($result); $this->affected_rows = sqlsrv_rows_affected($result);
return true; return true;
@@ -103,7 +105,7 @@ if (isset($_GET["mssql"])) {
} }
} }
class Min_Result { class Result {
var $_result, $_offset = 0, $_fields, $num_rows; var $_result, $_offset = 0, $_fields, $num_rows;
function __construct($result) { function __construct($result) {
@@ -134,7 +136,7 @@ if (isset($_GET["mssql"])) {
$this->_fields = sqlsrv_field_metadata($this->_result); $this->_fields = sqlsrv_field_metadata($this->_result);
} }
$field = $this->_fields[$this->_offset++]; $field = $this->_fields[$this->_offset++];
$return = new stdClass; $return = new \stdClass;
$return->name = $field["Name"]; $return->name = $field["Name"];
$return->orgname = $field["Name"]; $return->orgname = $field["Name"];
$return->type = ($field["Type"] == 1 ? 254 : 0); $return->type = ($field["Type"] == 1 ? 254 : 0);
@@ -152,106 +154,23 @@ if (isset($_GET["mssql"])) {
} }
} }
} elseif (extension_loaded("mssql")) { } elseif (extension_loaded("pdo_sqlsrv")) {
class Min_DB { class Db extends PdoDb {
var $extension = "MSSQL", $_link, $_result, $server_info, $affected_rows, $error; var $extension = "PDO_SQLSRV";
function connect($server, $username, $password) { function connect($server, $username, $password) {
$this->_link = @mssql_connect($server, $username, $password); $this->dsn("sqlsrv:Server=" . str_replace(":", ",", $server), $username, $password);
if ($this->_link) { return true;
$result = $this->query("SELECT SERVERPROPERTY('ProductLevel'), SERVERPROPERTY('Edition')");
if ($result) {
$row = $result->fetch_row();
$this->server_info = $this->result("sp_server_info 2", 2) . " [$row[0]] $row[1]";
}
} else {
$this->error = mssql_get_last_message();
}
return (bool) $this->_link;
}
function quote($string) {
$unicode = strlen($string) != strlen(utf8_decode($string));
return ($unicode ? "N" : "") . "'" . str_replace("'", "''", $string) . "'";
} }
function select_db($database) { function select_db($database) {
return mssql_select_db($database); // database selection is separated from the connection so dbname in DSN can't be used
} return $this->query(use_sql($database));
function query($query, $unbuffered = false) {
$result = @mssql_query($query, $this->_link); //! $unbuffered
$this->error = "";
if (!$result) {
$this->error = mssql_get_last_message();
return false;
}
if ($result === true) {
$this->affected_rows = mssql_rows_affected($this->_link);
return true;
}
return new Min_Result($result);
}
function multi_query($query) {
return $this->_result = $this->query($query);
}
function store_result() {
return $this->_result;
}
function next_result() {
return mssql_next_result($this->_result->_result);
}
function result($query, $field = 0) {
$result = $this->query($query);
if (!is_object($result)) {
return false;
}
return mssql_result($result->_result, 0, $field);
}
}
class Min_Result {
var $_result, $_offset = 0, $_fields, $num_rows;
function __construct($result) {
$this->_result = $result;
$this->num_rows = mssql_num_rows($result);
}
function fetch_assoc() {
return mssql_fetch_assoc($this->_result);
}
function fetch_row() {
return mssql_fetch_row($this->_result);
}
function num_rows() {
return mssql_num_rows($this->_result);
}
function fetch_field() {
$return = mssql_fetch_field($this->_result);
$return->orgtable = $return->table;
$return->orgname = $return->name;
return $return;
}
function seek($offset) {
mssql_data_seek($this->_result, $offset);
}
function __destruct() {
mssql_free_result($this->_result);
} }
} }
} elseif (extension_loaded("pdo_dblib")) { } elseif (extension_loaded("pdo_dblib")) {
class Min_DB extends Min_PDO { class Db extends PdoDb {
var $extension = "PDO_DBLIB"; var $extension = "PDO_DBLIB";
function connect($server, $username, $password) { function connect($server, $username, $password) {
@@ -260,40 +179,95 @@ if (isset($_GET["mssql"])) {
} }
function select_db($database) { function select_db($database) {
// database selection is separated from the connection so dbname in DSN can't be used return $this->query(use_sql($database));
return $this->query("USE " . idf_escape($database));
} }
} }
} }
class Min_Driver extends Min_SQL { class Driver extends SqlDriver {
static $possibleDrivers = array("SQLSRV", "PDO_SQLSRV", "PDO_DBLIB");
static $jush = "mssql";
var $editFunctions = array(
array(
"date|time" => "getdate",
), array(
"int|decimal|real|float|money|datetime" => "+/-",
"char|text" => "+",
)
);
var $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL");
var $functions = array("len", "lower", "round", "upper");
var $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
var $onActions = "NO ACTION|CASCADE|SET NULL|SET DEFAULT";
var $generated = array("PERSISTED", "VIRTUAL");
function __construct($connection) {
parent::__construct($connection);
$this->types = array( //! use sys.types
lang('Numbers') => array("tinyint" => 3, "smallint" => 5, "int" => 10, "bigint" => 20, "bit" => 1, "decimal" => 0, "real" => 12, "float" => 53, "smallmoney" => 10, "money" => 20),
lang('Date and time') => array("date" => 10, "smalldatetime" => 19, "datetime" => 19, "datetime2" => 19, "time" => 8, "datetimeoffset" => 10),
lang('Strings') => array("char" => 8000, "varchar" => 8000, "text" => 2147483647, "nchar" => 4000, "nvarchar" => 4000, "ntext" => 1073741823),
lang('Binary') => array("binary" => 8000, "varbinary" => 8000, "image" => 2147483647),
);
}
function insertUpdate($table, $rows, $primary) { function insertUpdate($table, $rows, $primary) {
foreach ($rows as $set) { $fields = fields($table);
$update = array(); $update = array();
$where = array(); $where = array();
foreach ($set as $key => $val) { $set = reset($rows);
$update[] = "$key = $val"; $columns = "c" . implode(", c", range(1, count($set)));
if (isset($primary[idf_unescape($key)])) { $c = 0;
$where[] = "$key = $val"; $insert = array();
} foreach ($set as $key => $val) {
$c++;
$name = idf_unescape($key);
if (!$fields[$name]["auto_increment"]) {
$insert[$key] = "c$c";
} }
//! can use only one query for all rows if (isset($primary[$name])) {
if (!queries("MERGE " . table($table) . " USING (VALUES(" . implode(", ", $set) . ")) AS source (c" . implode(", c", range(1, count($set))) . ") ON " . implode(" AND ", $where) //! source, c1 - possible conflict $where[] = "$key = c$c";
. " WHEN MATCHED THEN UPDATE SET " . implode(", ", $update) } else {
. " WHEN NOT MATCHED THEN INSERT (" . implode(", ", array_keys($set)) . ") VALUES (" . implode(", ", $set) . ");" // ; is mandatory $update[] = "$key = c$c";
)) {
return false;
} }
} }
return true; $values = array();
foreach ($rows as $set) {
$values[] = "(" . implode(", ", $set) . ")";
}
if ($where) {
$identity = queries("SET IDENTITY_INSERT " . table($table) . " ON");
$return = queries(
"MERGE " . table($table) . " USING (VALUES\n\t" . implode(",\n\t", $values) . "\n) AS source ($columns) ON " . implode(" AND ", $where) //! source, c1 - possible conflict
. ($update ? "\nWHEN MATCHED THEN UPDATE SET " . implode(", ", $update) : "")
. "\nWHEN NOT MATCHED THEN INSERT (" . implode(", ", array_keys($identity ? $set : $insert)) . ") VALUES (" . ($identity ? $columns : implode(", ", $insert)) . ");" // ; is mandatory
);
if ($identity) {
queries("SET IDENTITY_INSERT " . table($table) . " OFF");
}
} else {
$return = queries("INSERT INTO " . table($table) . " (" . implode(", ", array_keys($set)) . ") VALUES\n" . implode(",\n", $values));
}
return $return;
} }
function begin() { function begin() {
return queries("BEGIN TRANSACTION"); return queries("BEGIN TRANSACTION");
} }
function tableHelp($name, $is_view = false) {
$links = array(
"sys" => "catalog-views/sys-",
"INFORMATION_SCHEMA" => "information-schema-views/",
);
$link = $links[get_schema()];
if ($link) {
return "relational-databases/system-$link" . preg_replace('~_~', '-', strtolower($name)) . "-transact-sql";
}
}
} }
@@ -308,7 +282,7 @@ if (isset($_GET["mssql"])) {
function connect() { function connect() {
global $adminer; global $adminer;
$connection = new Min_DB; $connection = new Db;
$credentials = $adminer->credentials(); $credentials = $adminer->credentials();
if ($credentials[0] == "") { if ($credentials[0] == "") {
@@ -363,9 +337,11 @@ if (isset($_GET["mssql"])) {
function table_status($name = "") { function table_status($name = "") {
$return = array(); $return = array();
foreach (get_rows("SELECT ao.name AS Name, ao.type_desc AS Engine, (SELECT value FROM fn_listextendedproperty(default, 'SCHEMA', schema_name(schema_id), 'TABLE', ao.name, null, null)) AS Comment foreach (
get_rows("SELECT ao.name AS Name, ao.type_desc AS Engine, (SELECT value FROM fn_listextendedproperty(default, 'SCHEMA', schema_name(schema_id), 'TABLE', ao.name, null, null)) AS Comment
FROM sys.all_objects AS ao FROM sys.all_objects AS ao
WHERE schema_id = SCHEMA_ID(" . q(get_schema()) . ") AND type IN ('S', 'U', 'V') " . ($name != "" ? "AND name = " . q($name) : "ORDER BY name")) as $row) { WHERE schema_id = SCHEMA_ID(" . q(get_schema()) . ") AND type IN ('S', 'U', 'V') " . ($name != "" ? "AND name = " . q($name) : "ORDER BY name")) as $row
) {
if ($name != "") { if ($name != "") {
return $row; return $row;
} }
@@ -383,15 +359,19 @@ WHERE schema_id = SCHEMA_ID(" . q(get_schema()) . ") AND type IN ('S', 'U', 'V')
} }
function fields($table) { function fields($table) {
global $connection;
$comments = get_key_vals("SELECT objname, cast(value as varchar(max)) FROM fn_listextendedproperty('MS_DESCRIPTION', 'schema', " . q(get_schema()) . ", 'table', " . q($table) . ", 'column', NULL)"); $comments = get_key_vals("SELECT objname, cast(value as varchar(max)) FROM fn_listextendedproperty('MS_DESCRIPTION', 'schema', " . q(get_schema()) . ", 'table', " . q($table) . ", 'column', NULL)");
$return = array(); $return = array();
foreach (get_rows("SELECT c.max_length, c.precision, c.scale, c.name, c.is_nullable, c.is_identity, c.collation_name, t.name type, CAST(d.definition as text) [default], d.name default_constraint $table_id = $connection->result("SELECT object_id FROM sys.all_objects WHERE schema_id = SCHEMA_ID(" . q(get_schema()) . ") AND type IN ('S', 'U', 'V') AND name = " . q($table));
foreach (
get_rows("SELECT c.max_length, c.precision, c.scale, c.name, c.is_nullable, c.is_identity, c.collation_name, t.name type, CAST(d.definition as text) [default], d.name default_constraint, i.is_primary_key
FROM sys.all_columns c FROM sys.all_columns c
JOIN sys.all_objects o ON c.object_id = o.object_id
JOIN sys.types t ON c.user_type_id = t.user_type_id JOIN sys.types t ON c.user_type_id = t.user_type_id
LEFT JOIN sys.default_constraints d ON c.default_object_id = d.object_id LEFT JOIN sys.default_constraints d ON c.default_object_id = d.object_id
WHERE o.schema_id = SCHEMA_ID(" . q(get_schema()) . ") AND o.type IN ('S', 'U', 'V') AND o.name = " . q($table) LEFT JOIN sys.index_columns ic ON c.object_id = ic.object_id AND c.column_id = ic.column_id
) as $row) { LEFT JOIN sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
WHERE c.object_id = " . q($table_id)) as $row
) {
$type = $row["type"]; $type = $row["type"];
$length = (preg_match("~char|binary~", $type) $length = (preg_match("~char|binary~", $type)
? $row["max_length"] / ($type[0] == 'n' ? 2 : 1) ? $row["max_length"] / ($type[0] == 'n' ? 2 : 1)
@@ -408,22 +388,27 @@ WHERE o.schema_id = SCHEMA_ID(" . q(get_schema()) . ") AND o.type IN ('S', 'U',
"auto_increment" => $row["is_identity"], "auto_increment" => $row["is_identity"],
"collation" => $row["collation_name"], "collation" => $row["collation_name"],
"privileges" => array("insert" => 1, "select" => 1, "update" => 1), "privileges" => array("insert" => 1, "select" => 1, "update" => 1),
"primary" => $row["is_identity"], //! or indexes.is_primary_key "primary" => $row["is_primary_key"],
"comment" => $comments[$row["name"]], "comment" => $comments[$row["name"]],
); );
} }
foreach (get_rows("SELECT * FROM sys.computed_columns WHERE object_id = " . q($table_id)) as $row) {
$return[$row["name"]]["generated"] = ($row["is_persisted"] ? "PERSISTED" : "VIRTUAL");
$return[$row["name"]]["default"] = $row["definition"];
}
return $return; return $return;
} }
function indexes($table, $connection2 = null) { function indexes($table, $connection2 = null) {
$return = array(); $return = array();
// sp_statistics doesn't return information about primary key // sp_statistics doesn't return information about primary key
foreach (get_rows("SELECT i.name, key_ordinal, is_unique, is_primary_key, c.name AS column_name, is_descending_key foreach (
get_rows("SELECT i.name, key_ordinal, is_unique, is_primary_key, c.name AS column_name, is_descending_key
FROM sys.indexes i FROM sys.indexes i
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
WHERE OBJECT_NAME(i.object_id) = " . q($table) WHERE OBJECT_NAME(i.object_id) = " . q($table), $connection2) as $row
, $connection2) as $row) { ) {
$name = $row["name"]; $name = $row["name"];
$return[$name]["type"] = ($row["is_primary_key"] ? "PRIMARY" : ($row["is_unique"] ? "UNIQUE" : "INDEX")); $return[$name]["type"] = ($row["is_primary_key"] ? "PRIMARY" : ($row["is_unique"] ? "UNIQUE" : "INDEX"));
$return[$name]["lengths"] = array(); $return[$name]["lengths"] = array();
@@ -447,7 +432,7 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
} }
function information_schema($db) { function information_schema($db) {
return false; return get_schema() == "INFORMATION_SCHEMA";
} }
function error() { function error() {
@@ -460,7 +445,7 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
} }
function drop_databases($databases) { function drop_databases($databases) {
return queries("DROP DATABASE " . implode(", ", array_map('idf_escape', $databases))); return queries("DROP DATABASE " . implode(", ", array_map('Adminer\idf_escape', $databases)));
} }
function rename_database($name, $collation) { function rename_database($name, $collation) {
@@ -488,6 +473,9 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
$val[1] = preg_replace("~( COLLATE )'(\\w+)'~", '\1\2', $val[1]); $val[1] = preg_replace("~( COLLATE )'(\\w+)'~", '\1\2', $val[1]);
$comments[$field[0]] = $val[5]; $comments[$field[0]] = $val[5];
unset($val[5]); unset($val[5]);
if (preg_match('~ AS ~', $val[3])) {
unset($val[1], $val[2]);
}
if ($field[0] == "") { if ($field[0] == "") {
$alter["ADD"][] = "\n " . implode("", $val) . ($table == "" ? substr($foreign[$val[0]], 16 + strlen($val[0])) : ""); // 16 - strlen(" FOREIGN KEY ()") $alter["ADD"][] = "\n " . implode("", $val) . ($table == "" ? substr($foreign[$val[0]], 16 + strlen($val[0])) : ""); // 16 - strlen(" FOREIGN KEY ()")
} else { } else {
@@ -542,10 +530,12 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
} else { } else {
$index[] = idf_escape($val[1]) . " ON " . table($table); $index[] = idf_escape($val[1]) . " ON " . table($table);
} }
} elseif (!queries(($val[0] != "PRIMARY" } elseif (
? "CREATE $val[0] " . ($val[0] != "INDEX" ? "INDEX " : "") . idf_escape($val[1] != "" ? $val[1] : uniqid($table . "_")) . " ON " . table($table) !queries(($val[0] != "PRIMARY"
: "ALTER TABLE " . table($table) . " ADD PRIMARY KEY" ? "CREATE $val[0] " . ($val[0] != "INDEX" ? "INDEX " : "") . idf_escape($val[1] != "" ? $val[1] : uniqid($table . "_")) . " ON " . table($table)
) . " (" . implode(", ", $val[2]) . ")")) { : "ALTER TABLE " . table($table) . " ADD PRIMARY KEY"
) . " (" . implode(", ", $val[2]) . ")")
) {
return false; return false;
} }
} }
@@ -571,10 +561,14 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
function foreign_keys($table) { function foreign_keys($table) {
$return = array(); $return = array();
$on_actions = array("CASCADE", "NO ACTION", "SET NULL", "SET DEFAULT");
foreach (get_rows("EXEC sp_fkeys @fktable_name = " . q($table) . ", @fktable_owner = " . q(get_schema())) as $row) { foreach (get_rows("EXEC sp_fkeys @fktable_name = " . q($table) . ", @fktable_owner = " . q(get_schema())) as $row) {
$foreign_key = &$return[$row["FK_NAME"]]; $foreign_key = &$return[$row["FK_NAME"]];
$foreign_key["db"] = $row["PKTABLE_QUALIFIER"]; $foreign_key["db"] = $row["PKTABLE_QUALIFIER"];
$foreign_key["ns"] = $row["PKTABLE_OWNER"];
$foreign_key["table"] = $row["PKTABLE_NAME"]; $foreign_key["table"] = $row["PKTABLE_NAME"];
$foreign_key["on_update"] = $on_actions[$row["UPDATE_RULE"]];
$foreign_key["on_delete"] = $on_actions[$row["DELETE_RULE"]];
$foreign_key["source"][] = $row["FKCOLUMN_NAME"]; $foreign_key["source"][] = $row["FKCOLUMN_NAME"];
$foreign_key["target"][] = $row["PKCOLUMN_NAME"]; $foreign_key["target"][] = $row["PKCOLUMN_NAME"];
} }
@@ -586,11 +580,11 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
} }
function drop_views($views) { function drop_views($views) {
return queries("DROP VIEW " . implode(", ", array_map('table', $views))); return queries("DROP VIEW " . implode(", ", array_map('Adminer\table', $views)));
} }
function drop_tables($tables) { function drop_tables($tables) {
return queries("DROP TABLE " . implode(", ", array_map('table', $tables))); return queries("DROP TABLE " . implode(", ", array_map('Adminer\table', $tables)));
} }
function move_tables($tables, $views, $target) { function move_tables($tables, $views, $target) {
@@ -601,7 +595,8 @@ WHERE OBJECT_NAME(i.object_id) = " . q($table)
if ($name == "") { if ($name == "") {
return array(); return array();
} }
$rows = get_rows("SELECT s.name [Trigger], $rows = get_rows(
"SELECT s.name [Trigger],
CASE WHEN OBJECTPROPERTY(s.id, 'ExecIsInsertTrigger') = 1 THEN 'INSERT' WHEN OBJECTPROPERTY(s.id, 'ExecIsUpdateTrigger') = 1 THEN 'UPDATE' WHEN OBJECTPROPERTY(s.id, 'ExecIsDeleteTrigger') = 1 THEN 'DELETE' END [Event], CASE WHEN OBJECTPROPERTY(s.id, 'ExecIsInsertTrigger') = 1 THEN 'INSERT' WHEN OBJECTPROPERTY(s.id, 'ExecIsUpdateTrigger') = 1 THEN 'UPDATE' WHEN OBJECTPROPERTY(s.id, 'ExecIsDeleteTrigger') = 1 THEN 'DELETE' END [Event],
CASE WHEN OBJECTPROPERTY(s.id, 'ExecIsInsteadOfTrigger') = 1 THEN 'INSTEAD OF' ELSE 'AFTER' END [Timing], CASE WHEN OBJECTPROPERTY(s.id, 'ExecIsInsteadOfTrigger') = 1 THEN 'INSTEAD OF' ELSE 'AFTER' END [Timing],
c.text c.text
@@ -618,13 +613,14 @@ WHERE s.xtype = 'TR' AND s.name = " . q($name)
function triggers($table) { function triggers($table) {
$return = array(); $return = array();
foreach (get_rows("SELECT sys1.name, foreach (
get_rows("SELECT sys1.name,
CASE WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsertTrigger') = 1 THEN 'INSERT' WHEN OBJECTPROPERTY(sys1.id, 'ExecIsUpdateTrigger') = 1 THEN 'UPDATE' WHEN OBJECTPROPERTY(sys1.id, 'ExecIsDeleteTrigger') = 1 THEN 'DELETE' END [Event], CASE WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsertTrigger') = 1 THEN 'INSERT' WHEN OBJECTPROPERTY(sys1.id, 'ExecIsUpdateTrigger') = 1 THEN 'UPDATE' WHEN OBJECTPROPERTY(sys1.id, 'ExecIsDeleteTrigger') = 1 THEN 'DELETE' END [Event],
CASE WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsteadOfTrigger') = 1 THEN 'INSTEAD OF' ELSE 'AFTER' END [Timing] CASE WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsteadOfTrigger') = 1 THEN 'INSTEAD OF' ELSE 'AFTER' END [Timing]
FROM sysobjects sys1 FROM sysobjects sys1
JOIN sysobjects sys2 ON sys1.parent_obj = sys2.id JOIN sysobjects sys2 ON sys1.parent_obj = sys2.id
WHERE sys1.xtype = 'TR' AND sys2.name = " . q($table) WHERE sys1.xtype = 'TR' AND sys2.name = " . q($table)) as $row
) as $row) { // triggers are not schema-scoped ) { // triggers are not schema-scoped
$return[$row["name"]] = array($row["Timing"], $row["Event"]); $return[$row["name"]] = array($row["Timing"], $row["Event"]);
} }
return $return; return $return;
@@ -651,23 +647,63 @@ WHERE sys1.xtype = 'TR' AND sys2.name = " . q($table)
} }
function set_schema($schema) { function set_schema($schema) {
$_GET["ns"] = $schema;
return true; // ALTER USER is permanent return true; // ALTER USER is permanent
} }
function create_sql($table, $auto_increment, $style) {
global $driver;
if (is_view(table_status($table))) {
$view = view($table);
return "CREATE VIEW " . table($table) . " AS $view[select]";
}
$fields = array();
$primary = false;
foreach (fields($table) as $name => $field) {
$val = process_field($field, $field);
if ($val[6]) {
$primary = true;
}
$fields[] = implode("", $val);
}
foreach (indexes($table) as $name => $index) {
if (!$primary || $index["type"] != "PRIMARY") {
$columns = array();
foreach ($index["columns"] as $key => $val) {
$columns[] = idf_escape($val) . ($index["descs"][$key] ? " DESC" : "");
}
$name = idf_escape($name);
$fields[] = ($index["type"] == "INDEX" ? "INDEX $name" : "CONSTRAINT $name " . ($index["type"] == "UNIQUE" ? "UNIQUE" : "PRIMARY KEY")) . " (" . implode(", ", $columns) . ")";
}
}
foreach ($driver->checkConstraints($table) as $name => $check) {
$fields[] = "CONSTRAINT " . idf_escape($name) . " CHECK ($check)";
}
return "CREATE TABLE " . table($table) . " (\n\t" . implode(",\n\t", $fields) . "\n)";
}
function foreign_keys_sql($table) {
$fields = array();
foreach (foreign_keys($table) as $foreign) {
$fields[] = ltrim(format_foreign_key($foreign));
}
return ($fields ? "ALTER TABLE " . table($table) . " ADD\n\t" . implode(",\n\t", $fields) . ";\n\n" : "");
}
function truncate_sql($table) {
return "TRUNCATE TABLE " . table($table);
}
function use_sql($database) { function use_sql($database) {
return "USE " . idf_escape($database); return "USE " . idf_escape($database);
} }
function show_variables() { function trigger_sql($table) {
return array(); $return = "";
} foreach (triggers($table) as $name => $trigger) {
$return .= create_trigger(" ON " . table($table), trigger($name)) . ";";
function is_c_style_escapes() { }
return false; return $return;
}
function show_status() {
return array();
} }
function convert_field($field) { function convert_field($field) {
@@ -678,38 +714,6 @@ WHERE sys1.xtype = 'TR' AND sys2.name = " . q($table)
} }
function support($feature) { function support($feature) {
return preg_match('~^(check|comment|columns|database|drop_col|indexes|descidx|scheme|sql|table|trigger|view|view_trigger)$~', $feature); //! routine| return preg_match('~^(check|comment|columns|database|drop_col|dump|indexes|descidx|scheme|sql|table|trigger|view|view_trigger)$~', $feature); //! routine|
}
function driver_config() {
$types = array();
$structured_types = array();
foreach (array( //! use sys.types
lang('Numbers') => array("tinyint" => 3, "smallint" => 5, "int" => 10, "bigint" => 20, "bit" => 1, "decimal" => 0, "real" => 12, "float" => 53, "smallmoney" => 10, "money" => 20),
lang('Date and time') => array("date" => 10, "smalldatetime" => 19, "datetime" => 19, "datetime2" => 19, "time" => 8, "datetimeoffset" => 10),
lang('Strings') => array("char" => 8000, "varchar" => 8000, "text" => 2147483647, "nchar" => 4000, "nvarchar" => 4000, "ntext" => 1073741823),
lang('Binary') => array("binary" => 8000, "varbinary" => 8000, "image" => 2147483647),
) as $key => $val) {
$types += $val;
$structured_types[$key] = array_keys($val);
}
return array(
'possible_drivers' => array("SQLSRV", "MSSQL", "PDO_DBLIB"),
'jush' => "mssql",
'types' => $types,
'structured_types' => $structured_types,
'unsigned' => array(),
'operators' => array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL"),
'functions' => array("len", "lower", "round", "upper"),
'grouping' => array("avg", "count", "count distinct", "max", "min", "sum"),
'edit_functions' => array(
array(
"date|time" => "getdate",
), array(
"int|decimal|real|float|money|datetime" => "+/-",
"char|text" => "+",
)
),
);
} }
} }

View File

@@ -1,11 +1,13 @@
<?php <?php
namespace Adminer;
$drivers = array("server" => "MySQL") + $drivers; $drivers = array("server" => "MySQL") + $drivers;
if (!defined("DRIVER")) { if (!defined('Adminer\DRIVER')) {
define("DRIVER", "server"); // server - backwards compatibility define('Adminer\DRIVER', "server"); // server - backwards compatibility
// MySQLi supports everything, MySQL doesn't support multiple result sets, PDO_MySQL doesn't support orgtable // MySQLi supports everything, MySQL doesn't support multiple result sets, PDO_MySQL doesn't support orgtable
if (extension_loaded("mysqli")) { if (extension_loaded("mysqli")) {
class Min_DB extends MySQLi { class Db extends \MySQLi {
var $extension = "MySQLi"; var $extension = "MySQLi";
function __construct() { function __construct() {
@@ -27,7 +29,7 @@ if (!defined("DRIVER")) {
$database, $database,
(is_numeric($port) ? $port : ini_get("mysqli.default_port")), (is_numeric($port) ? $port : ini_get("mysqli.default_port")),
(!is_numeric($port) ? $port : $socket), (!is_numeric($port) ? $port : $socket),
($ssl ? (empty($ssl['cert']) ? 2048 : 64) : 0) // 2048 - MYSQLI_CLIENT_SSL, 64 - MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT (not available before PHP 5.6.16) ($ssl ? ($ssl['verify'] !== false ? 2048 : 64) : 0) // 2048 - MYSQLI_CLIENT_SSL, 64 - MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT (not available before PHP 5.6.16)
); );
$this->options(MYSQLI_OPT_LOCAL_INFILE, false); $this->options(MYSQLI_OPT_LOCAL_INFILE, false);
return $return; return $return;
@@ -57,7 +59,7 @@ if (!defined("DRIVER")) {
} }
} elseif (extension_loaded("mysql") && !((ini_bool("sql.safe_mode") || ini_bool("mysql.allow_local_infile")) && extension_loaded("pdo_mysql"))) { } elseif (extension_loaded("mysql") && !((ini_bool("sql.safe_mode") || ini_bool("mysql.allow_local_infile")) && extension_loaded("pdo_mysql"))) {
class Min_DB { class Db {
var var
$extension = "MySQL", ///< @var string extension name $extension = "MySQL", ///< @var string extension name
$server_info, ///< @var string server version $server_info, ///< @var string server version
@@ -127,7 +129,7 @@ if (!defined("DRIVER")) {
/** Send query /** Send query
* @param string * @param string
* @param bool * @param bool
* @return mixed bool or Min_Result * @return mixed bool or Result
*/ */
function query($query, $unbuffered = false) { function query($query, $unbuffered = false) {
$result = @($unbuffered ? mysql_unbuffered_query($query, $this->_link) : mysql_query($query, $this->_link)); // @ - mute mysql.trace_mode $result = @($unbuffered ? mysql_unbuffered_query($query, $this->_link) : mysql_query($query, $this->_link)); // @ - mute mysql.trace_mode
@@ -142,7 +144,7 @@ if (!defined("DRIVER")) {
$this->info = mysql_info($this->_link); $this->info = mysql_info($this->_link);
return true; return true;
} }
return new Min_Result($result); return new Result($result);
} }
/** Send query with more resultsets /** Send query with more resultsets
@@ -154,7 +156,7 @@ if (!defined("DRIVER")) {
} }
/** Get current resultset /** Get current resultset
* @return Min_Result * @return Result
*/ */
function store_result() { function store_result() {
return $this->_result; return $this->_result;
@@ -182,7 +184,7 @@ if (!defined("DRIVER")) {
} }
} }
class Min_Result { class Result {
var var
$num_rows, ///< @var int number of rows in the result $num_rows, ///< @var int number of rows in the result
$_result, $_offset = 0 ///< @access private $_result, $_offset = 0 ///< @access private
@@ -229,25 +231,25 @@ if (!defined("DRIVER")) {
} }
} elseif (extension_loaded("pdo_mysql")) { } elseif (extension_loaded("pdo_mysql")) {
class Min_DB extends Min_PDO { class Db extends PdoDb {
var $extension = "PDO_MySQL"; var $extension = "PDO_MySQL";
function connect($server, $username, $password) { function connect($server, $username, $password) {
global $adminer; global $adminer;
$options = array(PDO::MYSQL_ATTR_LOCAL_INFILE => false); $options = array(\PDO::MYSQL_ATTR_LOCAL_INFILE => false);
$ssl = $adminer->connectSsl(); $ssl = $adminer->connectSsl();
if ($ssl) { if ($ssl) {
if (!empty($ssl['key'])) { if ($ssl['key']) {
$options[PDO::MYSQL_ATTR_SSL_KEY] = $ssl['key']; $options[\PDO::MYSQL_ATTR_SSL_KEY] = $ssl['key'];
} }
if (!empty($ssl['cert'])) { if ($ssl['cert']) {
$options[PDO::MYSQL_ATTR_SSL_CERT] = $ssl['cert']; $options[\PDO::MYSQL_ATTR_SSL_CERT] = $ssl['cert'];
} }
if (!empty($ssl['ca'])) { if ($ssl['ca']) {
$options[PDO::MYSQL_ATTR_SSL_CA] = $ssl['ca']; $options[\PDO::MYSQL_ATTR_SSL_CA] = $ssl['ca'];
} }
if (!empty($ssl['verify'])) { if (isset($ssl['verify'])) {
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = $ssl['verify']; $options[\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = $ssl['verify'];
} }
} }
$this->dsn( $this->dsn(
@@ -269,7 +271,7 @@ if (!defined("DRIVER")) {
} }
function query($query, $unbuffered = false) { function query($query, $unbuffered = false) {
$this->pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, !$unbuffered); $this->pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, !$unbuffered);
return parent::query($query, $unbuffered); return parent::query($query, $unbuffered);
} }
} }
@@ -278,7 +280,52 @@ if (!defined("DRIVER")) {
class Min_Driver extends Min_SQL { class Driver extends SqlDriver {
static $possibleDrivers = array("MySQLi", "MySQL", "PDO_MySQL");
static $jush = "sql"; ///< @var string JUSH identifier
var $unsigned = array("unsigned", "zerofill", "unsigned zerofill");
var $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "REGEXP", "IN", "FIND_IN_SET", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL", "SQL");
var $functions = array("char_length", "date", "from_unixtime", "lower", "round", "floor", "ceil", "sec_to_time", "time_to_sec", "upper");
var $grouping = array("avg", "count", "count distinct", "group_concat", "max", "min", "sum");
function __construct($connection) {
parent::__construct($connection);
$this->types = array(
lang('Numbers') => array("tinyint" => 3, "smallint" => 5, "mediumint" => 8, "int" => 10, "bigint" => 20, "decimal" => 66, "float" => 12, "double" => 21),
lang('Date and time') => array("date" => 10, "datetime" => 19, "timestamp" => 19, "time" => 10, "year" => 4),
lang('Strings') => array("char" => 255, "varchar" => 65535, "tinytext" => 255, "text" => 65535, "mediumtext" => 16777215, "longtext" => 4294967295),
lang('Lists') => array("enum" => 65535, "set" => 64),
lang('Binary') => array("bit" => 20, "binary" => 255, "varbinary" => 65535, "tinyblob" => 255, "blob" => 65535, "mediumblob" => 16777215, "longblob" => 4294967295),
lang('Geometry') => array("geometry" => 0, "point" => 0, "linestring" => 0, "polygon" => 0, "multipoint" => 0, "multilinestring" => 0, "multipolygon" => 0, "geometrycollection" => 0),
);
$this->editFunctions = array(
array(
"char" => "md5/sha1/password/encrypt/uuid",
"binary" => "md5/sha1",
"date|time" => "now",
), array(
number_type() => "+/-",
"date" => "+ interval/- interval",
"time" => "addtime/subtime",
"char|text" => "concat",
)
);
if (min_version('5.7.8', 10.2, $connection)) {
$this->types[lang('Strings')]["json"] = 4294967295;
}
if (min_version('', 10.7, $connection)) {
$this->types[lang('Strings')]["uuid"] = 128;
$this->editFunctions[0]['uuid'] = 'uuid';
}
if (min_version(9, '', $connection)) {
$this->types[lang('Numbers')]["vector"] = 16383;
$this->editFunctions[0]['vector'] = 'string_to_vector';
}
if (min_version(5.7, 10.2, $connection)) {
$this->generated = array("STORED", "VIRTUAL");
}
}
function insert($table, $set) { function insert($table, $set) {
return ($set ? parent::insert($table, $set) : queries("INSERT INTO " . table($table) . " ()\nVALUES ()")); return ($set ? parent::insert($table, $set) : queries("INSERT INTO " . table($table) . " ()\nVALUES ()"));
@@ -335,7 +382,7 @@ if (!defined("DRIVER")) {
} }
} }
function tableHelp($name) { function tableHelp($name, $is_view = false) {
$maria = preg_match('~MariaDB~', $this->_conn->server_info); $maria = preg_match('~MariaDB~', $this->_conn->server_info);
if (information_schema(DB)) { if (information_schema(DB)) {
return strtolower("information-schema-" . ($maria ? "$name-table/" : str_replace("_", "-", $name) . "-table.html")); return strtolower("information-schema-" . ($maria ? "$name-table/" : str_replace("_", "-", $name) . "-table.html"));
@@ -345,6 +392,14 @@ if (!defined("DRIVER")) {
} }
} }
function hasCStyleEscapes() {
static $c_style;
if ($c_style === null) {
$sql_mode = $this->_conn->result("SHOW VARIABLES LIKE 'sql_mode'", 1);
$c_style = (strpos($sql_mode, 'NO_BACKSLASH_ESCAPES') === false);
}
return $c_style;
}
} }
@@ -366,29 +421,15 @@ if (!defined("DRIVER")) {
} }
/** Connect to the database /** Connect to the database
* @return mixed Min_DB or string for error * @return mixed Db or string for error
*/ */
function connect() { function connect() {
global $adminer, $types, $structured_types, $edit_functions; global $adminer;
$connection = new Min_DB; $connection = new Db;
$credentials = $adminer->credentials(); $credentials = $adminer->credentials();
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) { 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)); // available in MySQLi since PHP 5.0.5
$connection->query("SET sql_quote_show_create = 1, autocommit = 1"); $connection->query("SET sql_quote_show_create = 1, autocommit = 1");
if (min_version('5.7.8', 10.2, $connection)) {
$structured_types[lang('Strings')][] = "json";
$types["json"] = 4294967295;
}
if (min_version('', 10.7, $connection)) {
$structured_types[lang('Strings')][] = "uuid";
$types["uuid"] = 128;
$edit_functions[0]['uuid'] = 'uuid';
}
if (min_version(9, '', $connection)) {
$structured_types[lang('Numbers')][] = "vector";
$types["vector"] = 16383;
$edit_functions[0]['vector'] = 'string_to_vector';
}
return $connection; return $connection;
} }
$return = $connection->error; $return = $connection->error;
@@ -406,10 +447,7 @@ if (!defined("DRIVER")) {
// SHOW DATABASES can take a very long time so it is cached // SHOW DATABASES can take a very long time so it is cached
$return = get_session("dbs"); $return = get_session("dbs");
if ($return === null) { if ($return === null) {
$query = (min_version(5) $query = "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA ORDER BY SCHEMA_NAME"; // SHOW DATABASES can be disabled by skip_show_database
? "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA ORDER BY SCHEMA_NAME"
: "SHOW DATABASES"
); // SHOW DATABASES can be disabled by skip_show_database
$return = ($flush ? slow_query($query) : get_vals($query)); $return = ($flush ? slow_query($query) : get_vals($query));
restart_session(); restart_session();
set_session("dbs", $return); set_session("dbs", $return);
@@ -484,15 +522,12 @@ if (!defined("DRIVER")) {
* @return array [$name => $type] * @return array [$name => $type]
*/ */
function tables_list() { function tables_list() {
return get_key_vals(min_version(5) return get_key_vals("SELECT TABLE_NAME, TABLE_TYPE FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() ORDER BY TABLE_NAME");
? "SELECT TABLE_NAME, TABLE_TYPE FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() ORDER BY TABLE_NAME"
: "SHOW TABLES"
);
} }
/** Count tables in all databases /** Count tables in all databases
* @param array * @param array
* @return array arra($db => $tables) * @return array [$db => $tables]
*/ */
function count_tables($databases) { function count_tables($databases) {
$return = array(); $return = array();
@@ -505,14 +540,17 @@ if (!defined("DRIVER")) {
/** Get table status /** Get table status
* @param string * @param string
* @param bool return only "Name", "Engine" and "Comment" fields * @param bool return only "Name", "Engine" and "Comment" fields
* @return array [$name => array("Name" => , "Engine" => , "Comment" => , "Oid" => , "Rows" => , "Collation" => , "Auto_increment" => , "Data_length" => , "Index_length" => , "Data_free" => )] or only inner array with $name * @return array [$name => ["Name" => , "Engine" => , "Comment" => , "Oid" => , "Rows" => , "Collation" => , "Auto_increment" => , "Data_length" => , "Index_length" => , "Data_free" => ]] or only inner array with $name
*/ */
function table_status($name = "", $fast = false) { function table_status($name = "", $fast = false) {
$return = array(); $return = array();
foreach (get_rows($fast && min_version(5) foreach (
? "SELECT TABLE_NAME AS Name, ENGINE AS Engine, TABLE_COMMENT AS Comment FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() " . ($name != "" ? "AND TABLE_NAME = " . q($name) : "ORDER BY Name") get_rows(
: "SHOW TABLE STATUS" . ($name != "" ? " LIKE " . q(addcslashes($name, "%_\\")) : "") $fast
) as $row) { ? "SELECT TABLE_NAME AS Name, ENGINE AS Engine, TABLE_COMMENT AS Comment FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() " . ($name != "" ? "AND TABLE_NAME = " . q($name) : "ORDER BY Name")
: "SHOW TABLE STATUS" . ($name != "" ? " LIKE " . q(addcslashes($name, "%_\\")) : "")
) as $row
) {
if ($row["Engine"] == "InnoDB") { if ($row["Engine"] == "InnoDB") {
// ignore internal comment, unnecessary since MySQL 5.1.21 // ignore internal comment, unnecessary since MySQL 5.1.21
$row["Comment"] = preg_replace('~(?:(.+); )?InnoDB free: .*~', '\1', $row["Comment"]); $row["Comment"] = preg_replace('~(?:(.+); )?InnoDB free: .*~', '\1', $row["Comment"]);
@@ -549,28 +587,39 @@ if (!defined("DRIVER")) {
/** Get information about fields /** Get information about fields
* @param string * @param string
* @return array [$name => array("field" => , "full_type" => , "type" => , "length" => , "unsigned" => , "default" => , "null" => , "auto_increment" => , "on_update" => , "collation" => , "privileges" => , "comment" => , "primary" => )] * @return array [$name => ["field" => , "full_type" => , "type" => , "length" => , "unsigned" => , "default" => , "null" => , "auto_increment" => , "on_update" => , "collation" => , "privileges" => , "comment" => , "primary" => , "generated" => ]]
*/ */
function fields($table) { function fields($table) {
$return = array(); $return = array();
foreach (get_rows("SHOW FULL COLUMNS FROM " . table($table)) as $row) { foreach (get_rows("SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = " . q($table) . " ORDER BY ORDINAL_POSITION") as $row) {
preg_match('~^([^( ]+)(?:\((.+)\))?( unsigned)?( zerofill)?$~', $row["Type"], $match); $field = $row["COLUMN_NAME"];
$return[$row["Field"]] = array( $default = $row["COLUMN_DEFAULT"];
"field" => $row["Field"], $type = $row["COLUMN_TYPE"];
"full_type" => $row["Type"], $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);
$return[$field] = array(
"field" => $field,
"full_type" => $type,
"type" => $match[1], "type" => $match[1],
"length" => $match[2], "length" => $match[2],
"unsigned" => ltrim($match[3] . $match[4]), "unsigned" => ltrim($match[3] . $match[4]),
"default" => ($row["Default"] != "" || preg_match("~char|set~", $match[1]) ? (preg_match('~text~', $match[1]) ? stripslashes(preg_replace("~^'(.*)'\$~", '\1', $row["Default"])) : $row["Default"]) : null), "default" => ($generated
"null" => ($row["Null"] == "YES"), ? $row["GENERATION_EXPRESSION"]
"auto_increment" => ($row["Extra"] == "auto_increment"), : ($default != "" || preg_match("~char|set~", $match[1])
"on_update" => (preg_match('~^on update (.+)~i', $row["Extra"], $match) ? $match[1] : ""), //! available since MySQL 5.1.23 ? (preg_match('~text~', $match[1]) ? stripslashes(preg_replace("~^'(.*)'\$~", '\1', $default)) : $default)
"collation" => $row["Collation"], : null
"privileges" => array_flip(preg_split('~, *~', $row["Privileges"])), )
"comment" => $row["Comment"], ),
"primary" => ($row["Key"] == "PRI"), "null" => ($row["IS_NULLABLE"] == "YES"),
// https://mariadb.com/kb/en/library/show-columns/, https://github.com/vrana/adminer/pull/359#pullrequestreview-276677186 "auto_increment" => ($extra == "auto_increment"),
"generated" => preg_match('~^(VIRTUAL|PERSISTENT|STORED)~', $row["Extra"]), "on_update" => (preg_match('~\bon update (\w+)~i', $extra, $match) ? $match[1] : ""), //! available since MySQL 5.1.23
"collation" => $row["COLLATION_NAME"],
"privileges" => array_flip(explode(",", $row["PRIVILEGES"])),
"comment" => $row["COLUMN_COMMENT"],
"primary" => ($row["COLUMN_KEY"] == "PRI"),
"generated" => ($generated[1] == "PERSISTENT" ? "STORED" : $generated[1]),
); );
} }
return $return; return $return;
@@ -578,8 +627,8 @@ if (!defined("DRIVER")) {
/** Get table indexes /** Get table indexes
* @param string * @param string
* @param string Min_DB to use * @param string Db to use
* @return array [$key_name => array("type" => , "columns" => array(), "lengths" => array(), "descs" => array())] * @return array [$key_name => ["type" => , "columns" => [], "lengths" => [], "descs" => []]]
*/ */
function indexes($table, $connection2 = null) { function indexes($table, $connection2 = null) {
$return = array(); $return = array();
@@ -595,25 +644,25 @@ if (!defined("DRIVER")) {
/** Get foreign keys in table /** Get foreign keys in table
* @param string * @param string
* @return array [$name => array("db" => , "ns" => , "table" => , "source" => array(), "target" => array(), "on_delete" => , "on_update" => )] * @return array [$name => ["db" => , "ns" => , "table" => , "source" => [], "target" => [], "on_delete" => , "on_update" => ]]
*/ */
function foreign_keys($table) { function foreign_keys($table) {
global $connection, $on_actions; global $connection, $driver;
static $pattern = '(?:`(?:[^`]|``)+`|"(?:[^"]|"")+")'; static $pattern = '(?:`(?:[^`]|``)+`|"(?:[^"]|"")+")';
$return = array(); $return = array();
$create_table = $connection->result("SHOW CREATE TABLE " . table($table), 1); $create_table = $connection->result("SHOW CREATE TABLE " . table($table), 1);
if ($create_table) { if ($create_table) {
preg_match_all("~CONSTRAINT ($pattern) FOREIGN KEY ?\\(((?:$pattern,? ?)+)\\) REFERENCES ($pattern)(?:\\.($pattern))? \\(((?:$pattern,? ?)+)\\)(?: ON DELETE ($on_actions))?(?: ON UPDATE ($on_actions))?~", $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) { foreach ($matches as $match) {
preg_match_all("~$pattern~", $match[2], $source); preg_match_all("~$pattern~", $match[2], $source);
preg_match_all("~$pattern~", $match[5], $target); preg_match_all("~$pattern~", $match[5], $target);
$return[idf_unescape($match[1])] = array( $return[idf_unescape($match[1])] = array(
"db" => idf_unescape($match[4] != "" ? $match[3] : $match[4]), "db" => idf_unescape($match[4] != "" ? $match[3] : $match[4]),
"table" => idf_unescape($match[4] != "" ? $match[4] : $match[3]), "table" => idf_unescape($match[4] != "" ? $match[4] : $match[3]),
"source" => array_map('idf_unescape', $source[0]), "source" => array_map('Adminer\idf_unescape', $source[0]),
"target" => array_map('idf_unescape', $target[0]), "target" => array_map('Adminer\idf_unescape', $target[0]),
"on_delete" => ($match[6] ? $match[6] : "RESTRICT"), "on_delete" => ($match[6] ?: "RESTRICT"),
"on_update" => ($match[7] ? $match[7] : "RESTRICT"), "on_update" => ($match[7] ?: "RESTRICT"),
); );
} }
} }
@@ -653,7 +702,7 @@ if (!defined("DRIVER")) {
* @return bool * @return bool
*/ */
function information_schema($db) { function information_schema($db) {
return (min_version(5) && $db == "information_schema") return ($db == "information_schema")
|| (min_version(5.5) && $db == "performance_schema"); || (min_version(5.5) && $db == "performance_schema");
} }
@@ -731,7 +780,7 @@ if (!defined("DRIVER")) {
/** Run commands to create or alter table /** Run commands to create or alter table
* @param string "" to create * @param string "" to create
* @param string new name * @param string new name
* @param array of array($orig, $process_field, $after) * @param array of [$orig, $process_field, $after]
* @param array of strings * @param array of strings
* @param string * @param string
* @param string * @param string
@@ -743,10 +792,16 @@ if (!defined("DRIVER")) {
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) { function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
$alter = array(); $alter = array();
foreach ($fields as $field) { foreach ($fields as $field) {
$alter[] = ($field[1] if ($field[1]) {
? ($table != "" ? ($field[0] != "" ? "CHANGE " . idf_escape($field[0]) : "ADD") : " ") . " " . implode($field[1]) . ($table != "" ? $field[2] : "") $default = $field[1][3];
: "DROP " . idf_escape($field[0]) if (preg_match('~ GENERATED~', $default)) {
); $field[1][3] = $field[1][2];
$field[1][2] = $default;
}
$alter[] = ($table != "" ? ($field[0] != "" ? "CHANGE " . idf_escape($field[0]) : "ADD") : " ") . " " . implode($field[1]) . ($table != "" ? $field[2] : "");
} else {
$alter[] = "DROP " . idf_escape($field[0]);
}
} }
$alter = array_merge($alter, $foreign); $alter = array_merge($alter, $foreign);
$status = ($comment !== null ? " COMMENT=" . q($comment) : "") $status = ($comment !== null ? " COMMENT=" . q($comment) : "")
@@ -768,7 +823,7 @@ if (!defined("DRIVER")) {
/** Run commands to alter indexes /** Run commands to alter indexes
* @param string escaped table name * @param string escaped table name
* @param array of array("index type", "name", array("column definition", ...)) or array("index type", "name", "DROP") * @param array of ["index type", "name", ["column definition", ...]] or ["index type", "name", "DROP"]
* @return bool * @return bool
*/ */
function alter_indexes($table, $alter) { function alter_indexes($table, $alter) {
@@ -794,7 +849,7 @@ if (!defined("DRIVER")) {
* @return bool * @return bool
*/ */
function drop_views($views) { function drop_views($views) {
return queries("DROP VIEW " . implode(", ", array_map('table', $views))); return queries("DROP VIEW " . implode(", ", array_map('Adminer\table', $views)));
} }
/** Drop tables /** Drop tables
@@ -802,7 +857,7 @@ if (!defined("DRIVER")) {
* @return bool * @return bool
*/ */
function drop_tables($tables) { function drop_tables($tables) {
return queries("DROP TABLE " . implode(", ", array_map('table', $tables))); return queries("DROP TABLE " . implode(", ", array_map('Adminer\table', $tables)));
} }
/** Move tables to other schema /** Move tables to other schema
@@ -845,7 +900,8 @@ if (!defined("DRIVER")) {
queries("SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'"); queries("SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'");
foreach ($tables as $table) { foreach ($tables as $table) {
$name = ($target == DB ? table("copy_$table") : idf_escape($target) . "." . table($table)); $name = ($target == DB ? table("copy_$table") : idf_escape($target) . "." . table($table));
if (($_POST["overwrite"] && !queries("\nDROP TABLE IF EXISTS $name")) if (
($_POST["overwrite"] && !queries("\nDROP TABLE IF EXISTS $name"))
|| !queries("CREATE TABLE $name LIKE " . table($table)) || !queries("CREATE TABLE $name LIKE " . table($table))
|| !queries("INSERT INTO $name SELECT * FROM " . table($table)) || !queries("INSERT INTO $name SELECT * FROM " . table($table))
) { ) {
@@ -861,8 +917,10 @@ if (!defined("DRIVER")) {
foreach ($views as $table) { foreach ($views as $table) {
$name = ($target == DB ? table("copy_$table") : idf_escape($target) . "." . table($table)); $name = ($target == DB ? table("copy_$table") : idf_escape($target) . "." . table($table));
$view = view($table); $view = view($table);
if (($_POST["overwrite"] && !queries("DROP VIEW IF EXISTS $name")) if (
|| !queries("CREATE VIEW $name AS $view[select]")) { //! USE to avoid db.table ($_POST["overwrite"] && !queries("DROP VIEW IF EXISTS $name"))
|| !queries("CREATE VIEW $name AS $view[select]") //! USE to avoid db.table
) {
return false; return false;
} }
} }
@@ -883,7 +941,7 @@ if (!defined("DRIVER")) {
/** Get defined triggers /** Get defined triggers
* @param string * @param string
* @return array [$name => array($timing, $event)] * @return array [$name => [$timing, $event]]
*/ */
function triggers($table) { function triggers($table) {
$return = array(); $return = array();
@@ -894,7 +952,7 @@ if (!defined("DRIVER")) {
} }
/** Get trigger options /** Get trigger options
* @return array ["Timing" => array(), "Event" => array(), "Type" => array()] * @return array ["Timing" => [], "Event" => [], "Type" => []]
*/ */
function trigger_options() { function trigger_options() {
return array( return array(
@@ -907,14 +965,14 @@ if (!defined("DRIVER")) {
/** Get information about stored routine /** Get information about stored routine
* @param string * @param string
* @param string "FUNCTION" or "PROCEDURE" * @param string "FUNCTION" or "PROCEDURE"
* @return array ["fields" => array("field" => , "type" => , "length" => , "unsigned" => , "inout" => , "collation" => ), "returns" => , "definition" => , "language" => ] * @return array ["fields" => ["field" => , "type" => , "length" => , "unsigned" => , "inout" => , "collation" => ], "returns" => , "definition" => , "language" => ]
*/ */
function routine($name, $type) { function routine($name, $type) {
global $connection, $enum_length, $inout, $types; global $connection, $driver;
$aliases = array("bool", "boolean", "integer", "double precision", "real", "dec", "numeric", "fixed", "national char", "national varchar"); $aliases = array("bool", "boolean", "integer", "double precision", "real", "dec", "numeric", "fixed", "national char", "national varchar");
$space = "(?:\\s|/\\*[\s\S]*?\\*/|(?:#|-- )[^\n]*\n?|--\r?\n)"; $space = "(?:\\s|/\\*[\s\S]*?\\*/|(?:#|-- )[^\n]*\n?|--\r?\n)";
$type_pattern = "((" . implode("|", array_merge(array_keys($types), $aliases)) . ")\\b(?:\\s*\\(((?:[^'\")]|$enum_length)++)\\))?\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s,]+)['\"]?)?"; $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,]+)['\"]?)?";
$pattern = "$space*(" . ($type == "FUNCTION" ? "" : $inout) . ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern"; $pattern = "$space*(" . ($type == "FUNCTION" ? "" : $driver->inout) . ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern";
$create = $connection->result("SHOW CREATE $type " . idf_escape($name), 2); $create = $connection->result("SHOW CREATE $type " . idf_escape($name), 2);
preg_match("~\\(((?:$pattern\\s*,?)*)\\)\\s*" . ($type == "FUNCTION" ? "RETURNS\\s+$type_pattern\\s+" : "") . "(.*)~is", $create, $match); preg_match("~\\(((?:$pattern\\s*,?)*)\\)\\s*" . ($type == "FUNCTION" ? "RETURNS\\s+$type_pattern\\s+" : "") . "(.*)~is", $create, $match);
$fields = array(); $fields = array();
@@ -923,7 +981,7 @@ if (!defined("DRIVER")) {
$fields[] = array( $fields[] = array(
"field" => str_replace("``", "`", $param[2]) . $param[3], "field" => str_replace("``", "`", $param[2]) . $param[3],
"type" => strtolower($param[5]), "type" => strtolower($param[5]),
"length" => preg_replace_callback("~$enum_length~s", 'normalize_enum', $param[6]), "length" => preg_replace_callback("~$driver->enumLength~s", 'Adminer\normalize_enum', $param[6]),
"unsigned" => strtolower(preg_replace('~\s+~', ' ', trim("$param[8] $param[7]"))), "unsigned" => strtolower(preg_replace('~\s+~', ' ', trim("$param[8] $param[7]"))),
"null" => 1, "null" => 1,
"full_type" => $param[4], "full_type" => $param[4],
@@ -933,7 +991,7 @@ if (!defined("DRIVER")) {
} }
return array( return array(
"fields" => $fields, "fields" => $fields,
"comment" => $connection->result("SELECT ROUTINE_COMMENT FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB) . " AND ROUTINE_NAME = " . q($name)), "comment" => $connection->result("SELECT ROUTINE_COMMENT FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = DATABASE() AND ROUTINE_NAME = " . q($name)),
) + ($type != "FUNCTION" ? array("definition" => $match[11]) : array( ) + ($type != "FUNCTION" ? array("definition" => $match[11]) : array(
"returns" => array("type" => $match[12], "length" => $match[13], "unsigned" => $match[15], "collation" => $match[16]), "returns" => array("type" => $match[12], "length" => $match[13], "unsigned" => $match[15], "collation" => $match[16]),
"definition" => $match[17], "definition" => $match[17],
@@ -945,7 +1003,7 @@ if (!defined("DRIVER")) {
* @return array ["SPECIFIC_NAME" => , "ROUTINE_NAME" => , "ROUTINE_TYPE" => , "DTD_IDENTIFIER" => ] * @return array ["SPECIFIC_NAME" => , "ROUTINE_NAME" => , "ROUTINE_TYPE" => , "DTD_IDENTIFIER" => ]
*/ */
function routines() { function routines() {
return get_rows("SELECT ROUTINE_NAME AS SPECIFIC_NAME, ROUTINE_NAME, ROUTINE_TYPE, DTD_IDENTIFIER FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . q(DB)); return get_rows("SELECT ROUTINE_NAME AS SPECIFIC_NAME, ROUTINE_NAME, ROUTINE_TYPE, DTD_IDENTIFIER FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = DATABASE()");
} }
/** Get list of available routine languages /** Get list of available routine languages
@@ -973,9 +1031,9 @@ if (!defined("DRIVER")) {
} }
/** Explain select /** Explain select
* @param Min_DB * @param Db
* @param string * @param string
* @return Min_Result * @return Result
*/ */
function explain($connection, $query) { function explain($connection, $query) {
return $connection->query("EXPLAIN " . (min_version(5.1) && !min_version(5.7) ? "PARTITIONS " : "") . $query); return $connection->query("EXPLAIN " . (min_version(5.1) && !min_version(5.7) ? "PARTITIONS " : "") . $query);
@@ -990,35 +1048,40 @@ if (!defined("DRIVER")) {
return ($where || $table_status["Engine"] != "InnoDB" ? null : $table_status["Rows"]); return ($where || $table_status["Engine"] != "InnoDB" ? null : $table_status["Rows"]);
} }
/* Not used is MySQL but checked in compile.php:
/** Get user defined types /** Get user defined types
* @return array * @return array [$id => $name]
*/
function types() { function types() {
return array(); return array();
} }
/** Get values of user defined type
* @param int
* @return string
function type_values($id) {
return "";
}
/** Get existing schemas /** Get existing schemas
* @return array * @return array
*/
function schemas() { function schemas() {
return array(); return array();
} }
/** Get current schema /** Get current schema
* @return string * @return string
*/
function get_schema() { function get_schema() {
return ""; return "";
} }
/** Set current schema /** Set current schema
* @param string * @param string
* @param Min_DB * @param Db
* @return bool * @return bool
*/
function set_schema($schema, $connection2 = null) { function set_schema($schema, $connection2 = null) {
return true; return true;
} }
*/
/** Get SQL command to create table /** Get SQL command to create table
* @param string * @param string
@@ -1070,19 +1133,6 @@ if (!defined("DRIVER")) {
return get_key_vals("SHOW VARIABLES"); return get_key_vals("SHOW VARIABLES");
} }
/** Check if C-style escapes are supported
* @return bool
*/
function is_c_style_escapes() {
global $connection;
static $c_style;
if ($c_style === null) {
$sql_mode = $connection->result("SHOW VARIABLES LIKE 'sql_mode'", 1);
$c_style = (strpos($sql_mode, 'NO_BACKSLASH_ESCAPES') === false);
}
return $c_style;
}
/** Get process list /** Get process list
* @return array [$row] * @return array [$row]
*/ */
@@ -1137,7 +1187,7 @@ if (!defined("DRIVER")) {
* @return bool * @return bool
*/ */
function support($feature) { function support($feature) {
return !preg_match("~scheme|sequence|type|view_trigger|materializedview" . (min_version(8) ? "" : "|descidx" . (min_version(5.1) ? "" : "|event|partitioning" . (min_version(5) ? "" : "|routine|trigger|view"))) . (min_version('8.0.16', '10.2.1') ? "" : "|check") . "~", $feature); return !preg_match("~scheme|sequence|type|view_trigger|materializedview" . (min_version(8) ? "" : "|descidx" . (min_version(5.1) ? "" : "|event|partitioning")) . (min_version('8.0.16', '10.2.1') ? "" : "|check") . "~", $feature);
} }
/** Kill a process /** Kill a process
@@ -1151,7 +1201,7 @@ if (!defined("DRIVER")) {
/** Return query to get connection ID /** Return query to get connection ID
* @return string * @return string
*/ */
function connection_id(){ function connection_id() {
return "SELECT CONNECTION_ID()"; return "SELECT CONNECTION_ID()";
} }
@@ -1162,45 +1212,4 @@ if (!defined("DRIVER")) {
global $connection; global $connection;
return $connection->result("SELECT @@max_connections"); return $connection->result("SELECT @@max_connections");
} }
/** Get driver config
* @return array ['possible_drivers' => , 'jush' => , 'types' => , 'structured_types' => , 'unsigned' => , 'operators' => , 'functions' => , 'grouping' => , 'edit_functions' => ]
*/
function driver_config() {
$types = array(); ///< @var array [$type => $maximum_unsigned_length, ...]
$structured_types = array(); ///< @var array [$description => array($type, ...), ...]
foreach (array(
lang('Numbers') => array("tinyint" => 3, "smallint" => 5, "mediumint" => 8, "int" => 10, "bigint" => 20, "decimal" => 66, "float" => 12, "double" => 21),
lang('Date and time') => array("dat`e" => 10, "datetime" => 19, "timestamp" => 19, "time" => 10, "year" => 4),
lang('Strings') => array("char" => 255, "varchar" => 65535, "tinytext" => 255, "text" => 65535, "mediumtext" => 16777215, "longtext" => 4294967295),
lang('Lists') => array("enum" => 65535, "set" => 64),
lang('Binary') => array("bit" => 20, "binary" => 255, "varbinary" => 65535, "tinyblob" => 255, "blob" => 65535, "mediumblob" => 16777215, "longblob" => 4294967295),
lang('Geometry') => array("geometry" => 0, "point" => 0, "linestring" => 0, "polygon" => 0, "multipoint" => 0, "multilinestring" => 0, "multipolygon" => 0, "geometrycollection" => 0),
) as $key => $val) {
$types += $val;
$structured_types[$key] = array_keys($val);
}
return array(
'possible_drivers' => array("MySQLi", "MySQL", "PDO_MySQL"),
'jush' => "sql", ///< @var string JUSH identifier
'types' => $types,
'structured_types' => $structured_types,
'unsigned' => array("unsigned", "zerofill", "unsigned zerofill"), ///< @var array number variants
'operators' => array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "REGEXP", "IN", "FIND_IN_SET", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL", "SQL"), ///< @var array operators used in select
'functions' => array("char_length", "date", "from_unixtime", "lower", "round", "floor", "ceil", "sec_to_time", "time_to_sec", "upper"), ///< @var array functions used in select
'grouping' => array("avg", "count", "count distinct", "group_concat", "max", "min", "sum"), ///< @var array grouping functions used in select
'edit_functions' => array( ///< @var array of array("$type|$type2" => "$function/$function2") functions used in editing, [0] - edit and insert, [1] - edit only
array(
"char" => "md5/sha1/password/encrypt/uuid",
"binary" => "md5/sha1",
"date|time" => "now",
), array(
number_type() => "+/-",
"date" => "+ interval/- interval",
"time" => "addtime/subtime",
"char|text" => "concat",
)
),
);
}
} }

View File

@@ -1,10 +1,12 @@
<?php <?php
namespace Adminer;
$drivers["oracle"] = "Oracle (beta)"; $drivers["oracle"] = "Oracle (beta)";
if (isset($_GET["oracle"])) { if (isset($_GET["oracle"])) {
define("DRIVER", "oracle"); define('Adminer\DRIVER', "oracle");
if (extension_loaded("oci8")) { if (extension_loaded("oci8")) {
class Min_DB { class Db {
var $extension = "oci8", $_link, $_result, $server_info, $affected_rows, $errno, $error; var $extension = "oci8", $_link, $_result, $server_info, $affected_rows, $errno, $error;
var $_current_db; var $_current_db;
@@ -50,7 +52,7 @@ if (isset($_GET["oracle"])) {
restore_error_handler(); restore_error_handler();
if ($return) { if ($return) {
if (oci_num_fields($result)) { if (oci_num_fields($result)) {
return new Min_Result($result); return new Result($result);
} }
$this->affected_rows = oci_num_rows($result); $this->affected_rows = oci_num_rows($result);
oci_free_statement($result); oci_free_statement($result);
@@ -79,7 +81,7 @@ if (isset($_GET["oracle"])) {
} }
} }
class Min_Result { class Result {
var $_result, $_offset = 1, $num_rows; var $_result, $_offset = 1, $num_rows;
function __construct($result) { function __construct($result) {
@@ -105,7 +107,7 @@ if (isset($_GET["oracle"])) {
function fetch_field() { function fetch_field() {
$column = $this->_offset++; $column = $this->_offset++;
$return = new stdClass; $return = new \stdClass;
$return->name = oci_field_name($this->_result, $column); $return->name = oci_field_name($this->_result, $column);
$return->orgname = $return->name; $return->orgname = $return->name;
$return->type = oci_field_type($this->_result, $column); $return->type = oci_field_type($this->_result, $column);
@@ -119,7 +121,7 @@ if (isset($_GET["oracle"])) {
} }
} elseif (extension_loaded("pdo_oci")) { } elseif (extension_loaded("pdo_oci")) {
class Min_DB extends Min_PDO { class Db extends PdoDb {
var $extension = "PDO_OCI"; var $extension = "PDO_OCI";
var $_current_db; var $_current_db;
@@ -138,7 +140,34 @@ if (isset($_GET["oracle"])) {
class Min_Driver extends Min_SQL { class Driver extends SqlDriver {
static $possibleDrivers = array("OCI8", "PDO_OCI");
static $jush = "oracle";
var $editFunctions = array(
array( //! no parentheses
"date" => "current_date",
"timestamp" => "current_timestamp",
), array(
"number|float|double" => "+/-",
"date|timestamp" => "+ interval/- interval",
"char|clob" => "||",
)
);
var $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL");
var $functions = array("length", "lower", "round", "upper");
var $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
function __construct($connection) {
parent::__construct($connection);
$this->types = array(
lang('Numbers') => array("number" => 38, "binary_float" => 12, "binary_double" => 21),
lang('Date and time') => array("date" => 10, "timestamp" => 29, "interval year" => 12, "interval day" => 28), //! year(), day() to second()
lang('Strings') => array("char" => 2000, "varchar2" => 4000, "nchar" => 2000, "nvarchar2" => 4000, "clob" => 4294967295, "nclob" => 4294967295),
lang('Binary') => array("raw" => 2000, "long raw" => 2147483648, "blob" => 4294967295, "bfile" => 4294967296),
);
}
//! support empty $set in insert() //! support empty $set in insert()
@@ -157,14 +186,19 @@ if (isset($_GET["oracle"])) {
$where[] = "$key = $val"; $where[] = "$key = $val";
} }
} }
if (!(($where && queries("UPDATE " . table($table) . " SET " . implode(", ", $update) . " WHERE " . implode(" AND ", $where)) && $connection->affected_rows) if (
|| queries("INSERT INTO " . table($table) . " (" . implode(", ", array_keys($set)) . ") VALUES (" . implode(", ", $set) . ")") !(($where && queries("UPDATE " . table($table) . " SET " . implode(", ", $update) . " WHERE " . implode(" AND ", $where)) && $connection->affected_rows)
)) { || queries("INSERT INTO " . table($table) . " (" . implode(", ", array_keys($set)) . ") VALUES (" . implode(", ", $set) . ")"))
) {
return false; return false;
} }
} }
return true; return true;
} }
function hasCStyleEscapes() {
return true;
}
} }
@@ -179,7 +213,7 @@ if (isset($_GET["oracle"])) {
function connect() { function connect() {
global $adminer; global $adminer;
$connection = new Min_DB; $connection = new Db;
$credentials = $adminer->credentials(); $credentials = $adminer->credentials();
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) { if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
return $connection; return $connection;
@@ -188,7 +222,8 @@ if (isset($_GET["oracle"])) {
} }
function get_databases() { function get_databases() {
return get_vals("SELECT DISTINCT tablespace_name FROM ( return get_vals(
"SELECT DISTINCT tablespace_name FROM (
SELECT tablespace_name FROM user_tablespaces SELECT tablespace_name FROM user_tablespaces
UNION SELECT tablespace_name FROM all_tables WHERE tablespace_name IS NOT NULL UNION SELECT tablespace_name FROM all_tables WHERE tablespace_name IS NOT NULL
) )
@@ -223,7 +258,7 @@ ORDER BY 1"
function get_current_db() { function get_current_db() {
global $connection; global $connection;
$db = $connection->_current_db ? $connection->_current_db : DB; $db = $connection->_current_db ?: DB;
unset($connection->_current_db); unset($connection->_current_db);
return $db; return $db;
} }
@@ -237,13 +272,14 @@ ORDER BY 1"
function views_table($columns) { function views_table($columns) {
$owner = where_owner(''); $owner = where_owner('');
return "(SELECT $columns FROM all_views WHERE " . ($owner ? $owner : "rownum < 0") . ")"; return "(SELECT $columns FROM all_views WHERE " . ($owner ?: "rownum < 0") . ")";
} }
function tables_list() { function tables_list() {
$view = views_table("view_name"); $view = views_table("view_name");
$owner = where_owner(" AND "); $owner = where_owner(" AND ");
return get_key_vals("SELECT table_name, 'table' FROM all_tables WHERE tablespace_name = " . q(DB) . "$owner return get_key_vals(
"SELECT table_name, 'table' FROM all_tables WHERE tablespace_name = " . q(DB) . "$owner
UNION SELECT view_name, 'view' FROM $view UNION SELECT view_name, 'view' FROM $view
ORDER BY 1" ORDER BY 1"
); //! views don't have schema ); //! views don't have schema
@@ -264,10 +300,11 @@ ORDER BY 1"
$db = get_current_db(); $db = get_current_db();
$view = views_table("view_name"); $view = views_table("view_name");
$owner = where_owner(" AND "); $owner = where_owner(" AND ");
foreach (get_rows('SELECT table_name "Name", \'table\' "Engine", avg_row_len * num_rows "Data_length", num_rows "Rows" FROM all_tables WHERE tablespace_name = ' . q($db) . $owner . ($name != "" ? " AND table_name = $search" : "") . " foreach (
get_rows('SELECT table_name "Name", \'table\' "Engine", avg_row_len * num_rows "Data_length", num_rows "Rows" FROM all_tables WHERE tablespace_name = ' . q($db) . $owner . ($name != "" ? " AND table_name = $search" : "") . "
UNION SELECT view_name, 'view', 0, 0 FROM $view" . ($name != "" ? " WHERE view_name = $search" : "") . " UNION SELECT view_name, 'view', 0, 0 FROM $view" . ($name != "" ? " WHERE view_name = $search" : "") . "
ORDER BY 1" ORDER BY 1") as $row
) as $row) { ) {
if ($name != "") { if ($name != "") {
return $row; return $row;
} }
@@ -313,12 +350,14 @@ ORDER BY 1"
function indexes($table, $connection2 = null) { function indexes($table, $connection2 = null) {
$return = array(); $return = array();
$owner = where_owner(" AND ", "aic.table_owner"); $owner = where_owner(" AND ", "aic.table_owner");
foreach (get_rows("SELECT aic.*, ac.constraint_type, atc.data_default foreach (
get_rows("SELECT aic.*, ac.constraint_type, atc.data_default
FROM all_ind_columns aic FROM all_ind_columns aic
LEFT JOIN all_constraints ac ON aic.index_name = ac.constraint_name AND aic.table_name = ac.table_name AND aic.index_owner = ac.owner LEFT JOIN all_constraints ac ON aic.index_name = ac.constraint_name AND aic.table_name = ac.table_name AND aic.index_owner = ac.owner
LEFT JOIN all_tab_cols atc ON aic.column_name = atc.column_name AND aic.table_name = atc.table_name AND aic.index_owner = atc.owner LEFT JOIN all_tab_cols atc ON aic.column_name = atc.column_name AND aic.table_name = atc.table_name AND aic.index_owner = atc.owner
WHERE aic.table_name = " . q($table) . "$owner WHERE aic.table_name = " . q($table) . "$owner
ORDER BY ac.constraint_type, aic.column_position", $connection2) as $row) { ORDER BY ac.constraint_type, aic.column_position", $connection2) as $row
) {
$index_name = $row["INDEX_NAME"]; $index_name = $row["INDEX_NAME"];
$column_name = $row["DATA_DEFAULT"]; $column_name = $row["DATA_DEFAULT"];
$column_name = ($column_name ? trim($column_name, '"') : $row["COLUMN_NAME"]); // trim - possibly wrapped in quotes but never contains quotes inside $column_name = ($column_name ? trim($column_name, '"') : $row["COLUMN_NAME"]); // trim - possibly wrapped in quotes but never contains quotes inside
@@ -341,7 +380,7 @@ ORDER BY ac.constraint_type, aic.column_position", $connection2) as $row) {
} }
function information_schema($db) { function information_schema($db) {
return false; return get_schema() == "INFORMATION_SCHEMA";
} }
function error() { function error() {
@@ -464,7 +503,7 @@ AND c_src.TABLE_NAME = " . q($table);
function schemas() { function schemas() {
$return = get_vals("SELECT DISTINCT owner FROM dba_segments WHERE owner IN (SELECT username FROM dba_users WHERE default_tablespace NOT IN ('SYSTEM','SYSAUX')) ORDER BY 1"); $return = get_vals("SELECT DISTINCT owner FROM dba_segments WHERE owner IN (SELECT username FROM dba_users WHERE default_tablespace NOT IN ('SYSTEM','SYSAUX')) ORDER BY 1");
return ($return ? $return : get_vals("SELECT DISTINCT owner FROM all_tables WHERE tablespace_name = " . q(DB) . " ORDER BY 1")); return ($return ?: get_vals("SELECT DISTINCT owner FROM all_tables WHERE tablespace_name = " . q(DB) . " ORDER BY 1"));
} }
function get_schema() { function get_schema() {
@@ -484,10 +523,6 @@ AND c_src.TABLE_NAME = " . q($table);
return get_key_vals('SELECT name, display_value FROM v$parameter'); return get_key_vals('SELECT name, display_value FROM v$parameter');
} }
function is_c_style_escapes() {
return true;
}
function process_list() { 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 FROM v$session sess LEFT OUTER JOIN v$sql sql
@@ -512,38 +547,4 @@ ORDER BY PROCESS
function support($feature) { function support($feature) {
return preg_match('~^(columns|database|drop_col|indexes|descidx|processlist|scheme|sql|status|table|variables|view)$~', $feature); //! return preg_match('~^(columns|database|drop_col|indexes|descidx|processlist|scheme|sql|status|table|variables|view)$~', $feature); //!
} }
function driver_config() {
$types = array();
$structured_types = array();
foreach (array(
lang('Numbers') => array("number" => 38, "binary_float" => 12, "binary_double" => 21),
lang('Date and time') => array("date" => 10, "timestamp" => 29, "interval year" => 12, "interval day" => 28), //! year(), day() to second()
lang('Strings') => array("char" => 2000, "varchar2" => 4000, "nchar" => 2000, "nvarchar2" => 4000, "clob" => 4294967295, "nclob" => 4294967295),
lang('Binary') => array("raw" => 2000, "long raw" => 2147483648, "blob" => 4294967295, "bfile" => 4294967296),
) as $key => $val) {
$types += $val;
$structured_types[$key] = array_keys($val);
}
return array(
'possible_drivers' => array("OCI8", "PDO_OCI"),
'jush' => "oracle",
'types' => $types,
'structured_types' => $structured_types,
'unsigned' => array(),
'operators' => array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL"),
'functions' => array("length", "lower", "round", "upper"),
'grouping' => array("avg", "count", "count distinct", "max", "min", "sum"),
'edit_functions' => array(
array( //! no parentheses
"date" => "current_date",
"timestamp" => "current_timestamp",
), array(
"number|float|double" => "+/-",
"date|timestamp" => "+ interval/- interval",
"char|clob" => "||",
)
),
);
}
} }

View File

@@ -1,10 +1,12 @@
<?php <?php
namespace Adminer;
$drivers["pgsql"] = "PostgreSQL"; $drivers["pgsql"] = "PostgreSQL";
if (isset($_GET["pgsql"])) { if (isset($_GET["pgsql"])) {
define("DRIVER", "pgsql"); define('Adminer\DRIVER', "pgsql");
if (extension_loaded("pgsql")) { if (extension_loaded("pgsql")) {
class Min_DB { class Db {
var $extension = "PgSQL", $_link, $_result, $_string, $_database = true, $server_info, $affected_rows, $error, $timeout; var $extension = "PgSQL", $_link, $_result, $_string, $_database = true, $server_info, $affected_rows, $error, $timeout;
function _error($errno, $error) { function _error($errno, $error) {
@@ -77,7 +79,7 @@ if (isset($_GET["pgsql"])) {
$this->affected_rows = pg_affected_rows($result); $this->affected_rows = pg_affected_rows($result);
$return = true; $return = true;
} else { } else {
$return = new Min_Result($result); $return = new Result($result);
} }
if ($this->timeout) { if ($this->timeout) {
$this->timeout = 0; $this->timeout = 0;
@@ -112,7 +114,7 @@ if (isset($_GET["pgsql"])) {
} }
} }
class Min_Result { class Result {
var $_result, $_offset = 0, $num_rows; var $_result, $_offset = 0, $num_rows;
function __construct($result) { function __construct($result) {
@@ -130,7 +132,7 @@ if (isset($_GET["pgsql"])) {
function fetch_field() { function fetch_field() {
$column = $this->_offset++; $column = $this->_offset++;
$return = new stdClass; $return = new \stdClass;
if (function_exists('pg_field_table')) { if (function_exists('pg_field_table')) {
$return->orgtable = pg_field_table($this->_result, $column); $return->orgtable = pg_field_table($this->_result, $column);
} }
@@ -147,7 +149,7 @@ if (isset($_GET["pgsql"])) {
} }
} elseif (extension_loaded("pdo_pgsql")) { } elseif (extension_loaded("pdo_pgsql")) {
class Min_DB extends Min_PDO { class Db extends PdoDb {
var $extension = "PDO_PgSQL", $timeout; var $extension = "PDO_PgSQL", $timeout;
function connect($server, $username, $password) { function connect($server, $username, $password) {
@@ -193,7 +195,48 @@ if (isset($_GET["pgsql"])) {
class Min_Driver extends Min_SQL { class Driver extends SqlDriver {
static $possibleDrivers = array("PgSQL", "PDO_PgSQL");
static $jush = "pgsql";
var $operators = array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "ILIKE", "ILIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL"); // no "SQL" to avoid CSRF
var $functions = array("char_length", "lower", "round", "to_hex", "to_timestamp", "upper");
var $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
function __construct($connection) {
parent::__construct($connection);
$this->types = array( //! arrays
lang('Numbers') => array("smallint" => 5, "integer" => 10, "bigint" => 19, "boolean" => 1, "numeric" => 0, "real" => 7, "double precision" => 16, "money" => 20),
lang('Date and time') => array("date" => 13, "time" => 17, "timestamp" => 20, "timestamptz" => 21, "interval" => 0),
lang('Strings') => array("character" => 0, "character varying" => 0, "text" => 0, "tsquery" => 0, "tsvector" => 0, "uuid" => 0, "xml" => 0),
lang('Binary') => array("bit" => 0, "bit varying" => 0, "bytea" => 0),
lang('Network') => array("cidr" => 43, "inet" => 43, "macaddr" => 17, "macaddr8" => 23, "txid_snapshot" => 0),
lang('Geometry') => array("box" => 0, "circle" => 0, "line" => 0, "lseg" => 0, "path" => 0, "point" => 0, "polygon" => 0),
);
if (min_version(9.2, 0, $connection)) {
$this->types[lang('Strings')]["json"] = 4294967295;
if (min_version(9.4, 0, $connection)) {
$this->types[lang('Strings')]["jsonb"] = 4294967295;
}
}
$this->editFunctions = array(
array(
"char" => "md5",
"date|time" => "now",
), array(
number_type() => "+/-",
"date|time" => "+ interval/- interval", //! escape
"char|text" => "||",
)
);
if (min_version(12, 0, $connection)) {
$this->generated = array("STORED");
}
}
function setUserTypes($types) {
$this->types[lang('User types')] = array_flip($types);
}
function insertUpdate($table, $rows, $primary) { function insertUpdate($table, $rows, $primary) {
global $connection; global $connection;
@@ -206,9 +249,10 @@ if (isset($_GET["pgsql"])) {
$where[] = "$key = $val"; $where[] = "$key = $val";
} }
} }
if (!(($where && queries("UPDATE " . table($table) . " SET " . implode(", ", $update) . " WHERE " . implode(" AND ", $where)) && $connection->affected_rows) if (
|| queries("INSERT INTO " . table($table) . " (" . implode(", ", array_keys($set)) . ") VALUES (" . implode(", ", $set) . ")") !(($where && queries("UPDATE " . table($table) . " SET " . implode(", ", $update) . " WHERE " . implode(" AND ", $where)) && $connection->affected_rows)
)) { || queries("INSERT INTO " . table($table) . " (" . implode(", ", array_keys($set)) . ") VALUES (" . implode(", ", $set) . ")"))
) {
return false; return false;
} }
} }
@@ -238,10 +282,10 @@ if (isset($_GET["pgsql"])) {
return $this->_conn->warnings(); return $this->_conn->warnings();
} }
function tableHelp($name) { function tableHelp($name, $is_view = false) {
$links = array( $links = array(
"information_schema" => "infoschema", "information_schema" => "infoschema",
"pg_catalog" => "catalog", "pg_catalog" => ($is_view ? "view" : "catalog"),
); );
$link = $links[$_GET["ns"]]; $link = $links[$_GET["ns"]];
if ($link) { if ($link) {
@@ -249,6 +293,13 @@ if (isset($_GET["pgsql"])) {
} }
} }
function hasCStyleEscapes() {
static $c_style;
if ($c_style === null) {
$c_style = ($this->_conn->result("SHOW standard_conforming_strings") == "off");
}
return $c_style;
}
} }
@@ -262,20 +313,12 @@ if (isset($_GET["pgsql"])) {
} }
function connect() { function connect() {
global $adminer, $types, $structured_types; global $adminer;
$connection = new Min_DB; $connection = new Db;
$credentials = $adminer->credentials(); $credentials = $adminer->credentials();
if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) { if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
if (min_version(9, 0, $connection)) { if (min_version(9, 0, $connection)) {
$connection->query("SET application_name = 'Adminer'"); $connection->query("SET application_name = 'Adminer'");
if (min_version(9.2, 0, $connection)) {
$structured_types[lang('Strings')][] = "json";
$types["json"] = 4294967295;
if (min_version(9.4, 0, $connection)) {
$structured_types[lang('Strings')][] = "jsonb";
$types["jsonb"] = 4294967295;
}
}
} }
return $connection; return $connection;
} }
@@ -283,9 +326,9 @@ if (isset($_GET["pgsql"])) {
} }
function get_databases() { function get_databases() {
return get_vals("SELECT d.datname FROM pg_database d JOIN pg_roles r ON d.datdba = r.oid return get_vals("SELECT datname FROM pg_database
WHERE d.datallowconn = TRUE AND has_database_privilege(d.datname, 'CONNECT') AND pg_has_role(r.rolname, 'USAGE') WHERE datallowconn = TRUE AND has_database_privilege(datname, 'CONNECT')
ORDER BY d.datname"); ORDER BY datname");
} }
function limit($query, $where, $limit, $offset = 0, $separator = " ") { function limit($query, $where, $limit, $offset = 0, $separator = " ") {
@@ -315,7 +358,7 @@ ORDER BY d.datname");
function tables_list() { function tables_list() {
$query = "SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = current_schema()"; $query = "SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = current_schema()";
if (support('materializedview')) { // ' - support("materializedview") could be removed by compile.php if (support("materializedview")) {
$query .= " $query .= "
UNION ALL UNION ALL
SELECT matviewname, 'MATERIALIZED VIEW' SELECT matviewname, 'MATERIALIZED VIEW'
@@ -328,12 +371,20 @@ ORDER BY 1";
} }
function count_tables($databases) { function count_tables($databases) {
return array(); // would require reconnect global $connection;
$return = array();
foreach ($databases as $db) {
if ($connection->select_db($db)) {
$return[$db] = count(tables_list());
}
}
return $return;
} }
function table_status($name = "") { function table_status($name = "") {
$return = array(); $return = array();
foreach (get_rows("SELECT foreach (
get_rows("SELECT
c.relname AS \"Name\", c.relname AS \"Name\",
CASE c.relkind WHEN 'r' THEN 'table' WHEN 'm' THEN 'materialized view' ELSE 'view' END AS \"Engine\", CASE c.relkind WHEN 'r' THEN 'table' WHEN 'm' THEN 'materialized view' ELSE 'view' END AS \"Engine\",
pg_table_size(c.oid) AS \"Data_length\", pg_table_size(c.oid) AS \"Data_length\",
@@ -345,8 +396,8 @@ ORDER BY 1";
FROM pg_class c FROM pg_class c
JOIN pg_namespace n ON(n.nspname = current_schema() AND n.oid = c.relnamespace) JOIN pg_namespace n ON(n.nspname = current_schema() AND n.oid = c.relnamespace)
WHERE relkind IN ('r', 'm', 'v', 'f', 'p') WHERE relkind IN ('r', 'm', 'v', 'f', 'p')
" . ($name != "" ? "AND relname = " . q($name) : "ORDER BY relname") " . ($name != "" ? "AND relname = " . q($name) : "ORDER BY relname")) as $row //! Index_length, Auto_increment
) as $row) { //! Index_length, Auto_increment ) {
$return[$row["Name"]] = $row; $return[$row["Name"]] = $row;
} }
return ($name != "" ? $return[$name] : $return); return ($name != "" ? $return[$name] : $return);
@@ -366,7 +417,8 @@ WHERE relkind IN ('r', 'm', 'v', 'f', 'p')
'timestamp without time zone' => 'timestamp', 'timestamp without time zone' => 'timestamp',
'timestamp with time zone' => 'timestamptz', '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" : "") . " 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" : "") : "") . "
FROM pg_class c FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_attribute a ON c.oid = a.attrelid JOIN pg_attribute a ON c.oid = a.attrelid
@@ -375,8 +427,8 @@ WHERE c.relname = " . q($table) . "
AND n.nspname = current_schema() AND n.nspname = current_schema()
AND NOT a.attisdropped AND NOT a.attisdropped
AND a.attnum > 0 AND a.attnum > 0
ORDER BY a.attnum" ORDER BY a.attnum") as $row
) as $row) { ) {
//! collation, primary //! collation, primary
preg_match('~([^([]+)(\((.*)\))?([a-z ]+)?((\[[0-9]*])*)$~', $row["full_type"], $match); preg_match('~([^([]+)(\((.*)\))?([a-z ]+)?((\[[0-9]*])*)$~', $row["full_type"], $match);
list(, $type, $length, $row["length"], $addon, $array) = $match; list(, $type, $length, $row["length"], $addon, $array) = $match;
@@ -392,6 +444,7 @@ ORDER BY a.attnum"
if (in_array($row['attidentity'], array('a', 'd'))) { if (in_array($row['attidentity'], array('a', 'd'))) {
$row['default'] = 'GENERATED ' . ($row['attidentity'] == 'd' ? 'BY DEFAULT' : 'ALWAYS') . ' AS IDENTITY'; $row['default'] = 'GENERATED ' . ($row['attidentity'] == 'd' ? 'BY DEFAULT' : 'ALWAYS') . ' AS IDENTITY';
} }
$row["generated"] = ($row["attgenerated"] == "s" ? "STORED" : "");
$row["null"] = !$row["attnotnull"]; $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"]);
$row["privileges"] = array("insert" => 1, "select" => 1, "update" => 1); $row["privileges"] = array("insert" => 1, "select" => 1, "update" => 1);
@@ -411,16 +464,18 @@ ORDER BY a.attnum"
$return = array(); $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)); $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); $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", $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"]; $relname = $row["relname"];
$return[$relname]["type"] = ($row["indispartial"] ? "INDEX" : ($row["indisprimary"] ? "PRIMARY" : ($row["indisunique"] ? "UNIQUE" : "INDEX"))); $return[$relname]["type"] = ($row["indispartial"] ? "INDEX" : ($row["indisprimary"] ? "PRIMARY" : ($row["indisunique"] ? "UNIQUE" : "INDEX")));
$return[$relname]["columns"] = array(); $return[$relname]["columns"] = array();
foreach (explode(" ", $row["indkey"]) as $indkey) {
$return[$relname]["columns"][] = $columns[$indkey];
}
$return[$relname]["descs"] = array(); $return[$relname]["descs"] = array();
foreach (explode(" ", $row["indoption"]) as $indoption) { if ($row["indkey"]) {
$return[$relname]["descs"][] = ($indoption & 1 ? '1' : null); // 1 - INDOPTION_DESC foreach (explode(" ", $row["indkey"]) as $indkey) {
$return[$relname]["columns"][] = $columns[$indkey];
}
foreach (explode(" ", $row["indoption"]) as $indoption) {
$return[$relname]["descs"][] = ($indoption & 1 ? '1' : null); // 1 - INDOPTION_DESC
}
} }
$return[$relname]["lengths"] = array(); $return[$relname]["lengths"] = array();
} }
@@ -428,22 +483,24 @@ ORDER BY a.attnum"
} }
function foreign_keys($table) { function foreign_keys($table) {
global $on_actions; global $driver;
$return = array(); $return = array();
foreach (get_rows("SELECT conname, condeferrable::int AS deferrable, pg_get_constraintdef(oid) AS definition foreach (
get_rows("SELECT conname, condeferrable::int AS deferrable, pg_get_constraintdef(oid) AS definition
FROM pg_constraint FROM pg_constraint
WHERE conrelid = (SELECT pc.oid FROM pg_class AS pc INNER JOIN pg_namespace AS pn ON (pn.oid = pc.relnamespace) WHERE pc.relname = " . q($table) . " AND pn.nspname = current_schema()) WHERE conrelid = (SELECT pc.oid FROM pg_class AS pc INNER JOIN pg_namespace AS pn ON (pn.oid = pc.relnamespace) WHERE pc.relname = " . q($table) . " AND pn.nspname = current_schema())
AND contype = 'f'::char AND contype = 'f'::char
ORDER BY conkey, conname") as $row) { ORDER BY conkey, conname") as $row
) {
if (preg_match('~FOREIGN KEY\s*\((.+)\)\s*REFERENCES (.+)\((.+)\)(.*)$~iA', $row['definition'], $match)) { if (preg_match('~FOREIGN KEY\s*\((.+)\)\s*REFERENCES (.+)\((.+)\)(.*)$~iA', $row['definition'], $match)) {
$row['source'] = array_map('idf_unescape', array_map('trim', explode(',', $match[1]))); $row['source'] = array_map('Adminer\idf_unescape', array_map('trim', explode(',', $match[1])));
if (preg_match('~^(("([^"]|"")+"|[^"]+)\.)?"?("([^"]|"")+"|[^"]+)$~', $match[2], $match2)) { if (preg_match('~^(("([^"]|"")+"|[^"]+)\.)?"?("([^"]|"")+"|[^"]+)$~', $match[2], $match2)) {
$row['ns'] = idf_unescape($match2[2]); $row['ns'] = idf_unescape($match2[2]);
$row['table'] = idf_unescape($match2[4]); $row['table'] = idf_unescape($match2[4]);
} }
$row['target'] = array_map('idf_unescape', array_map('trim', explode(',', $match[3]))); $row['target'] = array_map('Adminer\idf_unescape', array_map('trim', explode(',', $match[3])));
$row['on_delete'] = (preg_match("~ON DELETE ($on_actions)~", $match[4], $match2) ? $match2[1] : 'NO ACTION'); $row['on_delete'] = (preg_match("~ON DELETE ($driver->onActions)~", $match[4], $match2) ? $match2[1] : 'NO ACTION');
$row['on_update'] = (preg_match("~ON UPDATE ($on_actions)~", $match[4], $match2) ? $match2[1] : 'NO ACTION'); $row['on_update'] = (preg_match("~ON UPDATE ($driver->onActions)~", $match[4], $match2) ? $match2[1] : 'NO ACTION');
$return[$row['conname']] = $row; $return[$row['conname']] = $row;
} }
} }
@@ -461,7 +518,7 @@ ORDER BY conkey, conname") as $row) {
} }
function information_schema($db) { function information_schema($db) {
return ($db == "information_schema"); return get_schema() == "information_schema";
} }
function error() { function error() {
@@ -522,9 +579,9 @@ ORDER BY conkey, conname") as $row) {
} }
$alter[] = "ALTER $column TYPE$val[1]"; $alter[] = "ALTER $column TYPE$val[1]";
$sequence_name = $table . "_" . idf_unescape($val[0]) . "_seq"; $sequence_name = $table . "_" . idf_unescape($val[0]) . "_seq";
$alter[] = "ALTER $column " . ($val[3] ? "SET$val[3]" $alter[] = "ALTER $column " . ($val[3] ? "SET" . preg_replace('~GENERATED ALWAYS(.*) STORED~', 'EXPRESSION\1', $val[3])
: (isset($val[6]) ? "SET DEFAULT nextval(" . q($sequence_name) . ")" : (isset($val[6]) ? "SET DEFAULT nextval(" . q($sequence_name) . ")"
: "DROP DEFAULT" : "DROP DEFAULT" //! change to DROP EXPRESSION with generated columns
)); ));
if (isset($val[6])) { if (isset($val[6])) {
$sequence = "CREATE SEQUENCE IF NOT EXISTS " . idf_escape($sequence_name) . " OWNED BY " . idf_escape($table) . ".$val[0]"; $sequence = "CREATE SEQUENCE IF NOT EXISTS " . idf_escape($sequence_name) . " OWNED BY " . idf_escape($table) . ".$val[0]";
@@ -548,9 +605,9 @@ ORDER BY conkey, conname") as $row) {
if ($comment !== null) { if ($comment !== null) {
$queries[] = "COMMENT ON TABLE " . table($name) . " IS " . q($comment); $queries[] = "COMMENT ON TABLE " . table($name) . " IS " . q($comment);
} }
if ($auto_increment != "") { // if ($auto_increment != "") {
//! $queries[] = "SELECT setval(pg_get_serial_sequence(" . q($name) . ", ), $auto_increment)"; //! $queries[] = "SELECT setval(pg_get_serial_sequence(" . q($name) . ", ), $auto_increment)";
} // }
foreach ($queries as $query) { foreach ($queries as $query) {
if (!queries($query)) { if (!queries($query)) {
return false; return false;
@@ -591,7 +648,7 @@ ORDER BY conkey, conname") as $row) {
} }
function truncate_tables($tables) { function truncate_tables($tables) {
return queries("TRUNCATE " . implode(", ", array_map('table', $tables))); return queries("TRUNCATE " . implode(", ", array_map('Adminer\table', $tables)));
return true; return true;
} }
@@ -601,10 +658,10 @@ ORDER BY conkey, conname") as $row) {
function drop_tables($tables) { function drop_tables($tables) {
foreach ($tables as $table) { foreach ($tables as $table) {
$status = table_status($table); $status = table_status($table);
if (!queries("DROP " . strtoupper($status["Engine"]) . " " . table($table))) { if (!queries("DROP " . strtoupper($status["Engine"]) . " " . table($table))) {
return false; return false;
} }
} }
return true; return true;
} }
@@ -701,18 +758,15 @@ ORDER BY SPECIFIC_NAME');
function found_rows($table_status, $where) { function found_rows($table_status, $where) {
global $connection; global $connection;
if (preg_match( if (preg_match("~ rows=([0-9]+)~", $connection->result("EXPLAIN SELECT * FROM " . idf_escape($table_status["Name"]) . ($where ? " WHERE " . implode(" AND ", $where) : "")), $regs)) {
"~ rows=([0-9]+)~",
$connection->result("EXPLAIN SELECT * FROM " . idf_escape($table_status["Name"]) . ($where ? " WHERE " . implode(" AND ", $where) : "")),
$regs
)) {
return $regs[1]; return $regs[1];
} }
return false; return false;
} }
function types() { function types() {
return get_key_vals("SELECT oid, typname return get_key_vals(
"SELECT oid, typname
FROM pg_type FROM pg_type
WHERE typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = current_schema()) WHERE typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = current_schema())
AND typtype IN ('b','d','e') AND typtype IN ('b','d','e')
@@ -720,6 +774,12 @@ AND typelem = 0"
); );
} }
function type_values($id) {
// to get values from type string: unnest(enum_range(NULL::"$type"))
$enums = get_vals("SELECT enumlabel FROM pg_enum WHERE enumtypid = $id ORDER BY enumsortorder");
return ($enums ? "'" . implode("', '", array_map('addslashes', $enums)) . "'" : "");
}
function schemas() { function schemas() {
return get_vals("SELECT nspname FROM pg_namespace ORDER BY nspname"); return get_vals("SELECT nspname FROM pg_namespace ORDER BY nspname");
} }
@@ -730,17 +790,12 @@ AND typelem = 0"
} }
function set_schema($schema, $connection2 = null) { function set_schema($schema, $connection2 = null) {
global $connection, $types, $structured_types; global $connection, $driver;
if (!$connection2) { if (!$connection2) {
$connection2 = $connection; $connection2 = $connection;
} }
$return = $connection2->query("SET search_path TO " . idf_escape($schema)); $return = $connection2->query("SET search_path TO " . idf_escape($schema));
foreach (types() as $key => $type) { //! get types from current_schemas('t') $driver->setUserTypes(types()); //! get types from current_schemas('t')
if (!isset($types[$type])) {
$types[$type] = $key;
$structured_types[lang('User types')][] = $type;
}
}
return $return; return $return;
} }
@@ -762,6 +817,7 @@ AND typelem = 0"
} }
function create_sql($table, $auto_increment, $style) { function create_sql($table, $auto_increment, $style) {
global $driver;
$return_parts = array(); $return_parts = array();
$sequences = array(); $sequences = array();
@@ -771,8 +827,6 @@ AND typelem = 0"
return rtrim("CREATE VIEW " . idf_escape($table) . " AS $view[select]", ";"); return rtrim("CREATE VIEW " . idf_escape($table) . " AS $view[select]", ";");
} }
$fields = fields($table); $fields = fields($table);
$indexes = indexes($table);
ksort($indexes);
if (!$status || empty($fields)) { if (!$status || empty($fields)) {
return false; return false;
@@ -790,10 +844,10 @@ AND typelem = 0"
// sequences for fields // sequences for fields
if (preg_match('~nextval\(\'([^\']+)\'\)~', $field['default'], $matches)) { if (preg_match('~nextval\(\'([^\']+)\'\)~', $field['default'], $matches)) {
$sequence_name = $matches[1]; $sequence_name = $matches[1];
$sq = reset(get_rows(min_version(10) $sq = reset(get_rows((min_version(10)
? "SELECT *, cache_size AS cache_value FROM pg_sequences WHERE schemaname = current_schema() AND sequencename = " . q(idf_unescape($sequence_name)) ? "SELECT *, cache_size AS cache_value FROM pg_sequences WHERE schemaname = current_schema() AND sequencename = " . q(idf_unescape($sequence_name))
: "SELECT * FROM $sequence_name" : "SELECT * FROM $sequence_name"
)); ), null, "-- "));
$sequences[] = ($style == "DROP+CREATE" ? "DROP SEQUENCE IF EXISTS $sequence_name;\n" : "") $sequences[] = ($style == "DROP+CREATE" ? "DROP SEQUENCE IF EXISTS $sequence_name;\n" : "")
. "CREATE SEQUENCE $sequence_name INCREMENT $sq[increment_by] MINVALUE $sq[min_value] MAXVALUE $sq[max_value]" . "CREATE SEQUENCE $sequence_name INCREMENT $sq[increment_by] MINVALUE $sq[min_value] MAXVALUE $sq[max_value]"
. ($auto_increment && $sq['last_value'] ? " START " . ($sq["last_value"] + 1) : "") . ($auto_increment && $sq['last_value'] ? " START " . ($sq["last_value"] + 1) : "")
@@ -807,41 +861,20 @@ AND typelem = 0"
$return = implode("\n\n", $sequences) . "\n\n$return"; $return = implode("\n\n", $sequences) . "\n\n$return";
} }
// primary + unique keys $primary = "";
foreach ($indexes as $index_name => $index) { foreach (indexes($table) as $index_name => $index) {
switch($index['type']) { if ($index['type'] == 'PRIMARY') {
case 'UNIQUE': $return_parts[] = "CONSTRAINT " . idf_escape($index_name) . " UNIQUE (" . implode(', ', array_map('idf_escape', $index['columns'])) . ")"; break; $primary = $index_name;
case 'PRIMARY': $return_parts[] = "CONSTRAINT " . idf_escape($index_name) . " PRIMARY KEY (" . implode(', ', array_map('idf_escape', $index['columns'])) . ")"; break; $return_parts[] = "CONSTRAINT " . idf_escape($index_name) . " PRIMARY KEY (" . implode(', ', array_map('Adminer\idf_escape', $index['columns'])) . ")";
} }
} }
$constraints = get_key_vals("SELECT conname, " . (min_version(8) ? "pg_get_constraintdef(pg_constraint.oid)" : "CONCAT('CHECK ', consrc)") . " foreach ($driver->checkConstraints($table) as $conname => $consrc) {
FROM pg_catalog.pg_constraint $return_parts[] = "CONSTRAINT " . idf_escape($conname) . " CHECK $consrc";
INNER JOIN pg_catalog.pg_namespace ON pg_constraint.connamespace = pg_namespace.oid
INNER JOIN pg_catalog.pg_class ON pg_constraint.conrelid = pg_class.oid AND pg_constraint.connamespace = pg_class.relnamespace
WHERE pg_constraint.contype = 'c'
AND conrelid != 0 -- handle only CONSTRAINTs here, not TYPES
AND nspname = current_schema()
AND relname = " . q($table) . "
ORDER BY connamespace, conname"
);
foreach ($constraints as $conname => $consrc) {
$return_parts[] = "CONSTRAINT " . idf_escape($conname) . " $consrc";
} }
$return .= implode(",\n ", $return_parts) . "\n) WITH (oids = " . ($status['Oid'] ? 'true' : 'false') . ");"; $return .= implode(",\n ", $return_parts) . "\n) WITH (oids = " . ($status['Oid'] ? 'true' : 'false') . ");";
// "basic" indexes after table definition
foreach ($indexes as $index_name => $index) {
if ($index['type'] == 'INDEX') {
$columns = array();
foreach ($index['columns'] as $key => $val) {
$columns[] = idf_escape($val) . ($index['descs'][$key] ? " DESC" : "");
}
$return .= "\n\nCREATE INDEX " . idf_escape($index_name) . " ON " . idf_escape($status['nspname']) . "." . idf_escape($status['Name']) . " USING btree (" . implode(', ', $columns) . ");";
}
}
// comments for table & fields // comments for table & fields
if ($status['Comment']) { if ($status['Comment']) {
$return .= "\n\nCOMMENT ON TABLE " . idf_escape($status['nspname']) . "." . idf_escape($status['Name']) . " IS " . q($status['Comment']) . ";"; $return .= "\n\nCOMMENT ON TABLE " . idf_escape($status['nspname']) . "." . idf_escape($status['Name']) . " IS " . q($status['Comment']) . ";";
@@ -853,6 +886,10 @@ ORDER BY connamespace, conname"
} }
} }
foreach (get_rows("SELECT indexdef FROM pg_catalog.pg_indexes WHERE schemaname = current_schema() AND tablename = " . q($table) . ($primary ? " AND indexname != " . q($primary) : ""), null, "-- ") as $row) {
$return .= "\n\n$row[indexdef];";
}
return rtrim($return, ';'); return rtrim($return, ';');
} }
@@ -879,22 +916,10 @@ ORDER BY connamespace, conname"
return get_key_vals("SHOW ALL"); return get_key_vals("SHOW ALL");
} }
function is_c_style_escapes() {
global $connection;
static $c_style;
if ($c_style === null) {
$c_style = ($connection->result("SHOW standard_conforming_strings") == "off");
}
return $c_style;
}
function process_list() { function process_list() {
return get_rows("SELECT * FROM pg_stat_activity ORDER BY " . (min_version(9.2) ? "pid" : "procpid")); return get_rows("SELECT * FROM pg_stat_activity ORDER BY " . (min_version(9.2) ? "pid" : "procpid"));
} }
function show_status() {
}
function convert_field($field) { function convert_field($field) {
} }
@@ -910,7 +935,7 @@ ORDER BY connamespace, conname"
return queries("SELECT pg_terminate_backend(" . number($val) . ")"); return queries("SELECT pg_terminate_backend(" . number($val) . ")");
} }
function connection_id(){ function connection_id() {
return "SELECT pg_backend_pid()"; return "SELECT pg_backend_pid()";
} }
@@ -918,40 +943,4 @@ ORDER BY connamespace, conname"
global $connection; global $connection;
return $connection->result("SHOW max_connections"); return $connection->result("SHOW max_connections");
} }
function driver_config() {
$types = array();
$structured_types = array();
foreach (array( //! arrays
lang('Numbers') => array("smallint" => 5, "integer" => 10, "bigint" => 19, "boolean" => 1, "numeric" => 0, "real" => 7, "double precision" => 16, "money" => 20),
lang('Date and time') => array("date" => 13, "time" => 17, "timestamp" => 20, "timestamptz" => 21, "interval" => 0),
lang('Strings') => array("character" => 0, "character varying" => 0, "text" => 0, "tsquery" => 0, "tsvector" => 0, "uuid" => 0, "xml" => 0),
lang('Binary') => array("bit" => 0, "bit varying" => 0, "bytea" => 0),
lang('Network') => array("cidr" => 43, "inet" => 43, "macaddr" => 17, "macaddr8" => 23, "txid_snapshot" => 0),
lang('Geometry') => array("box" => 0, "circle" => 0, "line" => 0, "lseg" => 0, "path" => 0, "point" => 0, "polygon" => 0),
) as $key => $val) { //! can be retrieved from pg_type
$types += $val;
$structured_types[$key] = array_keys($val);
}
return array(
'possible_drivers' => array("PgSQL", "PDO_PgSQL"),
'jush' => "pgsql",
'types' => $types,
'structured_types' => $structured_types,
'unsigned' => array(),
'operators' => array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "ILIKE", "ILIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL"), // no "SQL" to avoid CSRF
'functions' => array("char_length", "lower", "round", "to_hex", "to_timestamp", "upper"),
'grouping' => array("avg", "count", "count distinct", "max", "min", "sum"),
'edit_functions' => array(
array(
"char" => "md5",
"date|time" => "now",
), array(
number_type() => "+/-",
"date|time" => "+ interval/- interval", //! escape
"char|text" => "||",
)
),
);
}
} }

View File

@@ -1,185 +1,103 @@
<?php <?php
$drivers["sqlite"] = "SQLite 3"; namespace Adminer;
$drivers["sqlite2"] = "SQLite 2";
if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) { $drivers["sqlite"] = "SQLite";
define("DRIVER", (isset($_GET["sqlite"]) ? "sqlite" : "sqlite2"));
if (class_exists(isset($_GET["sqlite"]) ? "SQLite3" : "SQLiteDatabase")) {
if (isset($_GET["sqlite"])) {
class Min_SQLite { if (isset($_GET["sqlite"])) {
var $extension = "SQLite3", $server_info, $affected_rows, $errno, $error, $_link; define('Adminer\DRIVER', "sqlite");
if (class_exists("SQLite3")) {
function __construct($filename) { class SqliteDb {
$this->_link = new SQLite3($filename); var $extension = "SQLite3", $server_info, $affected_rows, $errno, $error, $_link;
$version = $this->_link->version();
$this->server_info = $version["versionString"];
}
function query($query) { function __construct($filename) {
$result = @$this->_link->query($query); $this->_link = new \SQLite3($filename);
$this->error = ""; $version = $this->_link->version();
if (!$result) { $this->server_info = $version["versionString"];
$this->errno = $this->_link->lastErrorCode();
$this->error = $this->_link->lastErrorMsg();
return false;
} elseif ($result->numColumns()) {
return new Min_Result($result);
}
$this->affected_rows = $this->_link->changes();
return true;
}
function quote($string) {
return (is_utf8($string)
? "'" . $this->_link->escapeString($string) . "'"
: "x'" . reset(unpack('H*', $string)) . "'"
);
}
function store_result() {
return $this->_result;
}
function result($query, $field = 0) {
$result = $this->query($query);
if (!is_object($result)) {
return false;
}
$row = $result->_result->fetchArray();
return $row ? $row[$field] : false;
}
} }
class Min_Result { function query($query) {
var $_result, $_offset = 0, $num_rows; $result = @$this->_link->query($query);
$this->error = "";
function __construct($result) { if (!$result) {
$this->_result = $result; $this->errno = $this->_link->lastErrorCode();
} $this->error = $this->_link->lastErrorMsg();
return false;
function fetch_assoc() { } elseif ($result->numColumns()) {
return $this->_result->fetchArray(SQLITE3_ASSOC); return new Result($result);
}
function fetch_row() {
return $this->_result->fetchArray(SQLITE3_NUM);
}
function fetch_field() {
$column = $this->_offset++;
$type = $this->_result->columnType($column);
return (object) array(
"name" => $this->_result->columnName($column),
"type" => $type,
"charsetnr" => ($type == SQLITE3_BLOB ? 63 : 0), // 63 - binary
);
}
function __desctruct() {
return $this->_result->finalize();
} }
$this->affected_rows = $this->_link->changes();
return true;
} }
} else { function quote($string) {
return (is_utf8($string)
class Min_SQLite { ? "'" . $this->_link->escapeString($string) . "'"
var $extension = "SQLite", $server_info, $affected_rows, $error, $_link; : "x'" . reset(unpack('H*', $string)) . "'"
);
function __construct($filename) {
$this->server_info = sqlite_libversion();
$this->_link = new SQLiteDatabase($filename);
}
function query($query, $unbuffered = false) {
$method = ($unbuffered ? "unbufferedQuery" : "query");
$result = @$this->_link->$method($query, SQLITE_BOTH, $error);
$this->error = "";
if (!$result) {
$this->error = $error;
return false;
} elseif ($result === true) {
$this->affected_rows = $this->changes();
return true;
}
return new Min_Result($result);
}
function quote($string) {
return "'" . sqlite_escape_string($string) . "'";
}
function store_result() {
return $this->_result;
}
function result($query, $field = 0) {
$result = $this->query($query);
if (!is_object($result)) {
return false;
}
$row = $result->_result->fetch();
return $row[$field];
}
} }
class Min_Result { function store_result() {
var $_result, $_offset = 0, $num_rows; return $this->_result;
function __construct($result) {
$this->_result = $result;
if (method_exists($result, 'numRows')) { // not available in unbuffered query
$this->num_rows = $result->numRows();
}
}
function fetch_assoc() {
$row = $this->_result->fetch(SQLITE_ASSOC);
if (!$row) {
return false;
}
$return = array();
foreach ($row as $key => $val) {
$return[idf_unescape($key)] = $val;
}
return $return;
}
function fetch_row() {
return $this->_result->fetch(SQLITE_NUM);
}
function fetch_field() {
$name = $this->_result->fieldName($this->_offset++);
$pattern = '(\[.*]|"(?:[^"]|"")*"|(.+))';
if (preg_match("~^($pattern\\.)?$pattern\$~", $name, $match)) {
$table = ($match[3] != "" ? $match[3] : idf_unescape($match[2]));
$name = ($match[5] != "" ? $match[5] : idf_unescape($match[4]));
}
return (object) array(
"name" => $name,
"orgname" => $name,
"orgtable" => $table,
);
}
} }
function result($query, $field = 0) {
$result = $this->query($query);
if (!is_object($result)) {
return false;
}
$row = $result->_result->fetchArray();
return $row ? $row[$field] : false;
}
}
class Result {
var $_result, $_offset = 0, $num_rows;
function __construct($result) {
$this->_result = $result;
}
function fetch_assoc() {
return $this->_result->fetchArray(SQLITE3_ASSOC);
}
function fetch_row() {
return $this->_result->fetchArray(SQLITE3_NUM);
}
function fetch_field() {
$column = $this->_offset++;
$type = $this->_result->columnType($column);
return (object) array(
"name" => $this->_result->columnName($column),
"type" => $type,
"charsetnr" => ($type == SQLITE3_BLOB ? 63 : 0), // 63 - binary
);
}
function __desctruct() {
return $this->_result->finalize();
}
} }
} elseif (extension_loaded("pdo_sqlite")) { } elseif (extension_loaded("pdo_sqlite")) {
class Min_SQLite extends Min_PDO { class SqliteDb extends PdoDb {
var $extension = "PDO_SQLite"; var $extension = "PDO_SQLite";
function __construct($filename) { function __construct($filename) {
$this->dsn(DRIVER . ":$filename", "", ""); $this->dsn(DRIVER . ":$filename", "", "");
} }
function select_db($db) {
return false;
}
} }
} }
if (class_exists("Min_SQLite")) { if (class_exists('Adminer\SqliteDb')) {
class Min_DB extends Min_SQLite { class Db extends SqliteDb {
function __construct() { function __construct() {
parent::__construct(":memory:"); parent::__construct(":memory:");
@@ -208,7 +126,36 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
class Min_Driver extends Min_SQL { class Driver extends SqlDriver {
static $possibleDrivers = array("SQLite3", "PDO_SQLite");
static $jush = "sqlite";
protected $types = array(array("integer" => 0, "real" => 0, "numeric" => 0, "text" => 0, "blob" => 0));
var $editFunctions = array(
array(
// "text" => "date('now')/time('now')/datetime('now')",
), array(
"integer|real|numeric" => "+/-",
// "text" => "date/time/datetime",
"text" => "||",
)
);
var $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL"); // REGEXP can be user defined function
var $functions = array("hex", "length", "lower", "round", "unixepoch", "upper");
var $grouping = array("avg", "count", "count distinct", "group_concat", "max", "min", "sum");
function __construct($connection) {
parent::__construct($connection);
if (min_version(3.31, 0, $connection)) {
$this->generated = array("STORED", "VIRTUAL");
}
}
function structuredTypes() {
return array_keys($this->types[0]);
}
function insertUpdate($table, $rows, $primary) { function insertUpdate($table, $rows, $primary) {
$values = array(); $values = array();
@@ -218,7 +165,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
return queries("REPLACE INTO " . table($table) . " (" . implode(", ", array_keys(reset($rows))) . ") VALUES\n" . implode(",\n", $values)); return queries("REPLACE INTO " . table($table) . " (" . implode(", ", array_keys(reset($rows))) . ") VALUES\n" . implode(",\n", $values));
} }
function tableHelp($name) { function tableHelp($name, $is_view = false) {
if ($name == "sqlite_sequence") { if ($name == "sqlite_sequence") {
return "fileformat2.html#seqtab"; return "fileformat2.html#seqtab";
} }
@@ -227,6 +174,10 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
} }
} }
function checkConstraints($table) {
preg_match_all('~ CHECK *(\( *(((?>[^()]*[^() ])|(?1))*) *\))~', $this->_conn->result("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = " . q($table)), $matches); //! could be inside a comment
return array_combine($matches[2], $matches[2]);
}
} }
@@ -245,7 +196,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
if ($password != "") { if ($password != "") {
return lang('Database does not support password.'); return lang('Database does not support password.');
} }
return new Min_DB; return new Db;
} }
function get_databases() { function get_databases() {
@@ -311,7 +262,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
global $connection; global $connection;
$return = array(); $return = array();
$primary = ""; $primary = "";
foreach (get_rows("PRAGMA table_info(" . table($table) . ")") as $row) { foreach (get_rows("PRAGMA table_" . (min_version(3.31) ? "x" : "") . "info(" . table($table) . ")") as $row) {
$name = $row["name"]; $name = $row["name"];
$type = strtolower($row["type"]); $type = strtolower($row["type"]);
$default = $row["dflt_value"]; $default = $row["dflt_value"];
@@ -334,13 +285,20 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
} }
} }
$sql = $connection->result("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = " . q($table)); $sql = $connection->result("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = " . q($table));
preg_match_all('~(("[^"]*+")+|[a-z0-9_]+)\s+text\s+COLLATE\s+(\'[^\']+\'|\S+)~i', $sql, $matches, PREG_SET_ORDER); $idf = '(("[^"]*+")+|[a-z0-9_]+)';
preg_match_all('~' . $idf . '\s+text\s+COLLATE\s+(\'[^\']+\'|\S+)~i', $sql, $matches, PREG_SET_ORDER);
foreach ($matches as $match) { foreach ($matches as $match) {
$name = str_replace('""', '"', preg_replace('~^"|"$~', '', $match[1])); $name = str_replace('""', '"', preg_replace('~^"|"$~', '', $match[1]));
if ($return[$name]) { if ($return[$name]) {
$return[$name]["collation"] = trim($match[3], "'"); $return[$name]["collation"] = trim($match[3], "'");
} }
} }
preg_match_all('~' . $idf . '\s.*GENERATED ALWAYS AS \((.+)\) (STORED|VIRTUAL)~i', $sql, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$name = str_replace('""', '"', preg_replace('~^"|"$~', '', $match[1]));
$return[$name]["default"] = $match[3];
$return[$name]["generated"] = strtoupper($match[4]);
}
return $return; return $return;
} }
@@ -395,7 +353,6 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
$return = array(); $return = array();
foreach (get_rows("PRAGMA foreign_key_list(" . table($table) . ")") as $row) { foreach (get_rows("PRAGMA foreign_key_list(" . table($table) . ")") as $row) {
$foreign_key = &$return[$row["id"]]; $foreign_key = &$return[$row["id"]];
//! idf_unescape in SQLite2
if (!$foreign_key) { if (!$foreign_key) {
$foreign_key = $row; $foreign_key = $row;
} }
@@ -407,7 +364,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
function view($name) { function view($name) {
global $connection; global $connection;
return array("select" => preg_replace('~^(?:[^`"[]+|`[^`]*`|"[^"]*")* AS\s+~iU', '', $connection->result("SELECT sql FROM sqlite_master WHERE name = " . q($name)))); //! identifiers may be inside [] return array("select" => preg_replace('~^(?:[^`"[]+|`[^`]*`|"[^"]*")* AS\s+~iU', '', $connection->result("SELECT sql FROM sqlite_master WHERE type = 'view' AND name = " . q($name)))); //! identifiers may be inside []
} }
function collations() { function collations() {
@@ -444,7 +401,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
return false; return false;
} }
try { try {
$link = new Min_SQLite($db); $link = new SqliteDb($db);
} catch (Exception $ex) { } catch (Exception $ex) {
$connection->error = $ex->getMessage(); $connection->error = $ex->getMessage();
return false; return false;
@@ -478,7 +435,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
} }
function auto_increment() { function auto_increment() {
return " PRIMARY KEY" . (DRIVER == "sqlite" ? " AUTOINCREMENT" : ""); return " PRIMARY KEY AUTOINCREMENT";
} }
function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) { function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
@@ -523,8 +480,20 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
return true; return true;
} }
function recreate_table($table, $name, $fields, $originals, $foreign, $auto_increment = 0, $indexes = array()) { /** Recreate table
global $connection; * @param string original name
* @param string new name
* @param array [process_field()], empty to preserve
* @param array [$original => idf_escape($new_column)], empty to preserve
* @param string [format_foreign_key()], empty to preserve
* @param int set auto_increment to this value, 0 to preserve
* @param array [[$type, $name, $columns]], empty to preserve
* @param string CHECK constraint to drop
* @param string CHECK constraint to add
* @return bool
*/
function recreate_table($table, $name, $fields, $originals, $foreign, $auto_increment = 0, $indexes = array(), $drop_check = "", $add_check = "") {
global $connection, $driver;
if ($table != "") { if ($table != "") {
if (!$fields) { if (!$fields) {
foreach (fields($table) as $key => $field) { foreach (fields($table) as $key => $field) {
@@ -582,16 +551,27 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
queries("BEGIN"); queries("BEGIN");
} }
foreach ($fields as $key => $field) { foreach ($fields as $key => $field) {
if (preg_match('~GENERATED~', $field[3])) {
unset($originals[array_search($field[0], $originals)]);
}
$fields[$key] = " " . implode($field); $fields[$key] = " " . implode($field);
} }
$fields = array_merge($fields, array_filter($foreign)); $fields = array_merge($fields, array_filter($foreign));
foreach ($driver->checkConstraints($table) as $check) {
if ($check != $drop_check) {
$fields[] = " CHECK ($check)";
}
}
if ($add_check) {
$fields[] = " CHECK ($add_check)";
}
$temp_name = ($table == $name ? "adminer_$name" : $name); $temp_name = ($table == $name ? "adminer_$name" : $name);
if (!queries("CREATE TABLE " . table($temp_name) . " (\n" . implode(",\n", $fields) . "\n)")) { if (!queries("CREATE TABLE " . table($temp_name) . " (\n" . implode(",\n", $fields) . "\n)")) {
// implicit ROLLBACK to not overwrite $connection->error // implicit ROLLBACK to not overwrite $connection->error
return false; return false;
} }
if ($table != "") { if ($table != "") {
if ($originals && !queries("INSERT INTO " . table($temp_name) . " (" . implode(", ", $originals) . ") SELECT " . implode(", ", array_map('idf_escape', array_keys($originals))) . " FROM " . table($table))) { if ($originals && !queries("INSERT INTO " . table($temp_name) . " (" . implode(", ", $originals) . ") SELECT " . implode(", ", array_map('Adminer\idf_escape', array_keys($originals))) . " FROM " . table($table))) {
return false; return false;
} }
$triggers = array(); $triggers = array();
@@ -600,7 +580,8 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
$triggers[] = "CREATE TRIGGER " . idf_escape($trigger_name) . " " . implode(" ", $timing_event) . " ON " . table($name) . "\n$trigger[Statement]"; $triggers[] = "CREATE TRIGGER " . idf_escape($trigger_name) . " " . implode(" ", $timing_event) . " ON " . table($name) . "\n$trigger[Statement]";
} }
$auto_increment = $auto_increment ? 0 : $connection->result("SELECT seq FROM sqlite_sequence WHERE name = " . q($table)); // if $auto_increment is set then it will be updated later $auto_increment = $auto_increment ? 0 : $connection->result("SELECT seq FROM sqlite_sequence WHERE name = " . q($table)); // if $auto_increment is set then it will be updated later
if (!queries("DROP TABLE " . table($table)) // drop before creating indexes and triggers to allow using old names if (
!queries("DROP TABLE " . table($table)) // drop before creating indexes and triggers to allow using old names
|| ($table == $name && !queries("ALTER TABLE " . table($temp_name) . " RENAME TO " . table($name))) || ($table == $name && !queries("ALTER TABLE " . table($temp_name) . " RENAME TO " . table($name)))
|| !alter_indexes($name, $indexes) || !alter_indexes($name, $indexes)
) { ) {
@@ -634,10 +615,11 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
} }
} }
foreach (array_reverse($alter) as $val) { foreach (array_reverse($alter) as $val) {
if (!queries($val[2] == "DROP" if (
!queries($val[2] == "DROP"
? "DROP INDEX " . idf_escape($val[1]) ? "DROP INDEX " . idf_escape($val[1])
: index_sql($table, $val[0], $val[1], "(" . implode(", ", $val[2]) . ")") : index_sql($table, $val[0], $val[1], "(" . implode(", ", $val[2]) . ")"))
)) { ) {
return false; return false;
} }
} }
@@ -720,18 +702,6 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
return array(); return array();
} }
function schemas() {
return array();
}
function get_schema() {
return "";
}
function set_schema($scheme) {
return true;
}
function create_sql($table, $auto_increment, $style) { function create_sql($table, $auto_increment, $style) {
global $connection; global $connection;
$return = $connection->result("SELECT sql FROM sqlite_master WHERE type IN ('table', 'view') AND name = " . q($table)); $return = $connection->result("SELECT sql FROM sqlite_master WHERE type IN ('table', 'view') AND name = " . q($table));
@@ -739,7 +709,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
if ($name == '') { if ($name == '') {
continue; continue;
} }
$return .= ";\n\n" . index_sql($table, $index['type'], $name, "(" . implode(", ", array_map('idf_escape', $index['columns'])) . ")"); $return .= ";\n\n" . index_sql($table, $index['type'], $name, "(" . implode(", ", array_map('Adminer\idf_escape', $index['columns'])) . ")");
} }
return $return; return $return;
} }
@@ -756,19 +726,18 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
} }
function show_variables() { function show_variables() {
global $connection;
$return = array(); $return = array();
$result = $connection->query("PRAGMA pragma_list"); foreach (get_rows("PRAGMA pragma_list") as $row) {
while ($row = $result->fetch_row()) { $name = $row["name"];
$return[$row[0]] = $connection->result("PRAGMA $row[0]"); if ($name != "pragma_list" && $name != "compile_options") {
foreach (get_rows("PRAGMA $name") as $row) {
$return[$name] .= implode(", ", $row) . "\n";
}
}
} }
return $return; return $return;
} }
function is_c_style_escapes() {
return true;
}
function show_status() { function show_status() {
$return = array(); $return = array();
foreach (get_vals("PRAGMA compile_options") as $option) { foreach (get_vals("PRAGMA compile_options") as $option) {
@@ -786,29 +755,6 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
} }
function support($feature) { function support($feature) {
return preg_match('~^(columns|database|drop_col|dump|indexes|descidx|move_col|sql|status|table|trigger|variables|view|view_trigger)$~', $feature); return preg_match('~^(check|columns|database|drop_col|dump|indexes|descidx|move_col|sql|status|table|trigger|variables|view|view_trigger)$~', $feature);
}
function driver_config() {
$types = array("integer" => 0, "real" => 0, "numeric" => 0, "text" => 0, "blob" => 0);
return array(
'possible_drivers' => array((isset($_GET["sqlite"]) ? "SQLite3" : "SQLite"), "PDO_SQLite"),
'jush' => "sqlite",
'types' => $types,
'structured_types' => array_keys($types),
'unsigned' => array(),
'operators' => array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL", "SQL"), // REGEXP can be user defined function
'functions' => array("hex", "length", "lower", "round", "unixepoch", "upper"),
'grouping' => array("avg", "count", "count distinct", "group_concat", "max", "min", "sum"),
'edit_functions' => array(
array(
// "text" => "date('now')/time('now')/datetime('now')",
), array(
"integer|real|numeric" => "+/-",
// "text" => "date/time/datetime",
"text" => "||",
)
),
);
} }
} }

View File

@@ -1,21 +1,24 @@
<?php <?php
namespace Adminer;
$TABLE = $_GET["dump"]; $TABLE = $_GET["dump"];
if ($_POST && !$error) { if ($_POST && !$error) {
$cookie = ""; $cookie = "";
foreach (array("output", "format", "db_style", "routines", "events", "table_style", "auto_increment", "triggers", "data_style") as $key) { foreach (array("output", "format", "db_style", "types", "routines", "events", "table_style", "auto_increment", "triggers", "data_style") as $key) {
$cookie .= "&$key=" . urlencode($_POST[$key]); $cookie .= "&$key=" . urlencode($_POST[$key]);
} }
cookie("adminer_export", substr($cookie, 1)); cookie("adminer_export", substr($cookie, 1));
$tables = array_flip((array) $_POST["tables"]) + array_flip((array) $_POST["data"]); $tables = array_flip((array) $_POST["tables"]) + array_flip((array) $_POST["data"]);
$ext = dump_headers( $ext = dump_headers(
(count($tables) == 1 ? key($tables) : DB), (count($tables) == 1 ? key($tables) : DB),
(DB == "" || count($tables) > 1)); (DB == "" || count($tables) > 1)
);
$is_sql = preg_match('~sql~', $_POST["format"]); $is_sql = preg_match('~sql~', $_POST["format"]);
if ($is_sql) { if ($is_sql) {
echo "-- Adminer $VERSION " . $drivers[DRIVER] . " " . str_replace("\n", " ", $connection->server_info) . " dump\n\n"; echo "-- Adminer $VERSION " . $drivers[DRIVER] . " " . str_replace("\n", " ", $connection->server_info) . " dump\n\n";
if ($jush == "sql") { if (JUSH == "sql") {
echo "SET NAMES utf8; echo "SET NAMES utf8;
SET time_zone = '+00:00'; SET time_zone = '+00:00';
SET foreign_key_checks = 0; SET foreign_key_checks = 0;
@@ -52,6 +55,18 @@ SET foreign_key_checks = 0;
} }
$out = ""; $out = "";
if ($_POST["types"]) {
foreach (types() as $id => $type) {
$enums = type_values($id);
if ($enums) {
$out .= ($style != 'DROP+CREATE' ? "DROP TYPE IF EXISTS " . idf_escape($type) . ";;\n" : "") . "CREATE TYPE " . idf_escape($type) . " AS ENUM ($enums);\n\n";
} else {
//! https://github.com/postgres/postgres/blob/REL_17_4/src/bin/pg_dump/pg_dump.c#L10846
$out .= "-- Could not export type $type\n\n";
}
}
}
if ($_POST["routines"]) { if ($_POST["routines"]) {
foreach (routines() as $row) { foreach (routines() as $row) {
$name = $row["ROUTINE_NAME"]; $name = $row["ROUTINE_NAME"];
@@ -70,7 +85,7 @@ SET foreign_key_checks = 0;
} }
} }
echo ($out && $jush == 'sql' ? "DELIMITER ;;\n\n$out" . "DELIMITER ;\n\n" : $out); echo ($out && JUSH == 'sql' ? "DELIMITER ;;\n\n$out" . "DELIMITER ;\n\n" : $out);
} }
if ($_POST["table_style"] || $_POST["data_style"]) { if ($_POST["table_style"] || $_POST["data_style"]) {
@@ -105,7 +120,7 @@ SET foreign_key_checks = 0;
} }
// add FKs after creating tables (except in MySQL which uses SET FOREIGN_KEY_CHECKS=0) // add FKs after creating tables (except in MySQL which uses SET FOREIGN_KEY_CHECKS=0)
if (function_exists('foreign_keys_sql')) { if (function_exists('Adminer\foreign_keys_sql')) {
foreach (table_status('', true) as $name => $table_status) { foreach (table_status('', true) as $name => $table_status) {
$table = (DB == "" || in_array($name, (array) $_POST["tables"])); $table = (DB == "" || in_array($name, (array) $_POST["tables"]));
if ($table && !is_view($table_status)) { if ($table && !is_view($table_status)) {
@@ -126,7 +141,7 @@ SET foreign_key_checks = 0;
} }
if ($is_sql) { if ($is_sql) {
echo "-- " . $connection->result("SELECT NOW()") . "\n"; echo "-- " . gmdate("Y-m-d H:i:s e") . "\n";
} }
exit; exit;
} }
@@ -140,7 +155,7 @@ page_header(lang('Export'), $error, ($_GET["export"] != "" ? array("table" => $_
$db_style = array('', 'USE', 'DROP+CREATE', 'CREATE'); $db_style = array('', 'USE', 'DROP+CREATE', 'CREATE');
$table_style = array('', 'DROP+CREATE', 'CREATE'); $table_style = array('', 'DROP+CREATE', 'CREATE');
$data_style = array('', 'TRUNCATE+INSERT', 'INSERT'); $data_style = array('', 'TRUNCATE+INSERT', 'INSERT');
if ($jush == "sql") { //! use insertUpdate() in all drivers if (JUSH == "sql") { //! use insertUpdate() in all drivers
$data_style[] = 'INSERT+UPDATE'; $data_style[] = 'INSERT+UPDATE';
} }
parse_str($_COOKIE["adminer_export"], $row); parse_str($_COOKIE["adminer_export"], $row);
@@ -156,7 +171,8 @@ echo "<tr><th>" . lang('Output') . "<td>" . html_select("output", $adminer->dump
echo "<tr><th>" . lang('Format') . "<td>" . html_select("format", $adminer->dumpFormat(), $row["format"], 0) . "\n"; // 0 - radio echo "<tr><th>" . lang('Format') . "<td>" . html_select("format", $adminer->dumpFormat(), $row["format"], 0) . "\n"; // 0 - radio
echo ($jush == "sqlite" ? "" : "<tr><th>" . lang('Database') . "<td>" . html_select('db_style', $db_style, $row["db_style"]) echo (JUSH == "sqlite" ? "" : "<tr><th>" . lang('Database') . "<td>" . html_select('db_style', $db_style, $row["db_style"])
. (support("type") ? checkbox("types", 1, $row["types"], lang('User types')) : "")
. (support("routine") ? checkbox("routines", 1, $row["routines"], lang('Routines')) : "") . (support("routine") ? checkbox("routines", 1, $row["routines"], lang('Routines')) : "")
. (support("event") ? checkbox("events", 1, $row["events"], lang('Events')) : "") . (support("event") ? checkbox("events", 1, $row["events"], lang('Events')) : "")
); );

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$TABLE = $_GET["edit"]; $TABLE = $_GET["edit"];
$fields = fields($TABLE); $fields = fields($TABLE);
$where = (isset($_GET["select"]) ? ($_POST["check"] && count($_POST["check"]) == 1 ? where_check($_POST["check"][0], $fields) : "") : where($_GET, $fields)); $where = (isset($_GET["select"]) ? ($_POST["check"] && count($_POST["check"]) == 1 ? where_check($_POST["check"][0], $fields) : "") : where($_GET, $fields));
@@ -70,7 +72,7 @@ if ($_POST["save"]) {
if ($_POST["clone"] && $field["auto_increment"]) { if ($_POST["clone"] && $field["auto_increment"]) {
$as = "''"; $as = "''";
} }
if ($jush == "sql" && preg_match("~enum|set~", $field["type"])) { if (JUSH == "sql" && preg_match("~enum|set~", $field["type"])) {
$as = "1*" . idf_escape($name); $as = "1*" . idf_escape($name);
} }
$select[] = ($as ? "$as AS " : "") . idf_escape($name); $select[] = ($as ? "$as AS " : "") . idf_escape($name);

View File

@@ -1,4 +1,6 @@
<?php <?php
// To create Adminer just for Elasticsearch, run `../compile.php elastic`.
function adminer_object() { function adminer_object() {
include_once "../plugins/plugin.php"; include_once "../plugins/plugin.php";
include_once "../plugins/login-password-less.php"; include_once "../plugins/login-password-less.php";

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$EVENT = $_GET["event"]; $EVENT = $_GET["event"];
$intervals = array("YEAR", "QUARTER", "MONTH", "DAY", "HOUR", "MINUTE", "WEEK", "SECOND", "YEAR_MONTH", "DAY_HOUR", "DAY_MINUTE", "DAY_SECOND", "HOUR_MINUTE", "HOUR_SECOND", "MINUTE_SECOND"); $intervals = array("YEAR", "QUARTER", "MONTH", "DAY", "HOUR", "MINUTE", "WEEK", "SECOND", "YEAR_MONTH", "DAY_HOUR", "DAY_MINUTE", "DAY_SECOND", "HOUR_MINUTE", "HOUR_SECOND", "MINUTE_SECOND");
$statuses = array("ENABLED" => "ENABLE", "DISABLED" => "DISABLE", "SLAVESIDE_DISABLED" => "DISABLE ON SLAVE"); $statuses = array("ENABLED" => "ENABLE", "DISABLED" => "DISABLE", "SLAVESIDE_DISABLED" => "DISABLE ON SLAVE");
@@ -16,13 +18,17 @@ if ($_POST && !$error) {
) . " ON COMPLETION" . ($row["ON_COMPLETION"] ? "" : " NOT") . " PRESERVE" ) . " ON COMPLETION" . ($row["ON_COMPLETION"] ? "" : " NOT") . " PRESERVE"
; ;
queries_redirect(substr(ME, 0, -1), ($EVENT != "" ? lang('Event has been altered.') : lang('Event has been created.')), queries(($EVENT != "" queries_redirect(
? "ALTER EVENT " . idf_escape($EVENT) . $schedule substr(ME, 0, -1),
. ($EVENT != $row["EVENT_NAME"] ? "\nRENAME TO " . idf_escape($row["EVENT_NAME"]) : "") ($EVENT != "" ? lang('Event has been altered.') : lang('Event has been created.')),
: "CREATE EVENT " . idf_escape($row["EVENT_NAME"]) . $schedule queries(
) . "\n" . $statuses[$row["STATUS"]] . " COMMENT " . q($row["EVENT_COMMENT"]) ($EVENT != ""
. rtrim(" DO\n$row[EVENT_DEFINITION]", ";") . ";" ? "ALTER EVENT " . idf_escape($EVENT) . $schedule . ($EVENT != $row["EVENT_NAME"] ? "\nRENAME TO " . idf_escape($row["EVENT_NAME"]) : "")
)); : "CREATE EVENT " . idf_escape($row["EVENT_NAME"]) . $schedule
) . "\n" . $statuses[$row["STATUS"]] . " COMMENT " . q($row["EVENT_COMMENT"])
. rtrim(" DO\n$row[EVENT_DEFINITION]", ";") . ";"
)
);
} }
} }
@@ -47,6 +53,8 @@ if (!$row && $EVENT != "") {
<p><?php textarea("EVENT_DEFINITION", $row["EVENT_DEFINITION"]); ?> <p><?php textarea("EVENT_DEFINITION", $row["EVENT_DEFINITION"]); ?>
<p> <p>
<input type="submit" value="<?php echo lang('Save'); ?>"> <input type="submit" value="<?php echo lang('Save'); ?>">
<?php if ($EVENT != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $EVENT)); ?><?php } ?> <?php if ($EVENT != "") { ?>
<input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $EVENT)); ?>
<?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>"> <input type="hidden" name="token" value="<?php echo $token; ?>">
</form> </form>

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
// caching headers added in compile.php // caching headers added in compile.php
if ($_GET["file"] == "favicon.ico") { if ($_GET["file"] == "favicon.ico") {
@@ -12,15 +14,34 @@ if ($_GET["file"] == "favicon.ico") {
echo lzw_decompress(compile_file('../adminer/static/functions.js;static/editing.js', 'minify_js')); echo lzw_decompress(compile_file('../adminer/static/functions.js;static/editing.js', 'minify_js'));
} elseif ($_GET["file"] == "jush.js") { } elseif ($_GET["file"] == "jush.js") {
header("Content-Type: text/javascript; charset=utf-8"); header("Content-Type: text/javascript; charset=utf-8");
echo lzw_decompress(compile_file('../externals/jush/modules/jush.js;../externals/jush/modules/jush-textarea.js;../externals/jush/modules/jush-txt.js;../externals/jush/modules/jush-js.js;../externals/jush/modules/jush-sql.js;../externals/jush/modules/jush-pgsql.js;../externals/jush/modules/jush-sqlite.js;../externals/jush/modules/jush-mssql.js;../externals/jush/modules/jush-oracle.js;../externals/jush/modules/jush-simpledb.js', 'minify_js')); echo lzw_decompress(compile_file('../externals/jush/modules/jush.js;
../externals/jush/modules/jush-textarea.js;
../externals/jush/modules/jush-txt.js;
../externals/jush/modules/jush-js.js;
../externals/jush/modules/jush-sql.js;
../externals/jush/modules/jush-pgsql.js;
../externals/jush/modules/jush-sqlite.js;
../externals/jush/modules/jush-mssql.js;
../externals/jush/modules/jush-oracle.js;
../externals/jush/modules/jush-simpledb.js', 'minify_js'));
} else { } else {
header("Content-Type: image/gif"); header("Content-Type: image/gif");
switch ($_GET["file"]) { switch ($_GET["file"]) {
case "plus.gif": echo compile_file('../adminer/static/plus.gif'); break; case "plus.gif":
case "cross.gif": echo compile_file('../adminer/static/cross.gif'); break; echo compile_file('../adminer/static/plus.gif');
case "up.gif": echo compile_file('../adminer/static/up.gif'); break; break;
case "down.gif": echo compile_file('../adminer/static/down.gif'); break; case "cross.gif":
case "arrow.gif": echo compile_file('../adminer/static/arrow.gif'); break; echo compile_file('../adminer/static/cross.gif');
break;
case "up.gif":
echo compile_file('../adminer/static/up.gif');
break;
case "down.gif":
echo compile_file('../adminer/static/down.gif');
break;
case "arrow.gif":
echo compile_file('../adminer/static/arrow.gif');
break;
} }
} }
exit; exit;

View File

@@ -1,12 +1,11 @@
<?php <?php
namespace Adminer;
$TABLE = $_GET["foreign"]; $TABLE = $_GET["foreign"];
$name = $_GET["name"]; $name = $_GET["name"];
$row = $_POST; $row = $_POST;
if ($_POST && !$error && !$_POST["add"] && !$_POST["change"] && !$_POST["change-js"]) { if ($_POST && !$error && !$_POST["add"] && !$_POST["change"] && !$_POST["change-js"]) {
$message = ($_POST["drop"] ? lang('Foreign key has been dropped.') : ($name != "" ? lang('Foreign key has been altered.') : lang('Foreign key has been created.')));
$location = ME . "table=" . urlencode($TABLE);
if (!$_POST["drop"]) { if (!$_POST["drop"]) {
$row["source"] = array_filter($row["source"], 'strlen'); $row["source"] = array_filter($row["source"], 'strlen');
ksort($row["source"]); // enforce input order ksort($row["source"]); // enforce input order
@@ -17,18 +16,23 @@ if ($_POST && !$error && !$_POST["add"] && !$_POST["change"] && !$_POST["change-
$row["target"] = $target; $row["target"] = $target;
} }
if ($jush == "sqlite") { if (JUSH == "sqlite") {
queries_redirect($location, $message, recreate_table($TABLE, $TABLE, array(), array(), array(" $name" => ($_POST["drop"] ? "" : " " . format_foreign_key($row))))); $result = recreate_table($TABLE, $TABLE, array(), array(), array(" $name" => ($row["drop"] ? "" : " " . format_foreign_key($row))));
} else { } else {
$alter = "ALTER TABLE " . table($TABLE); $alter = "ALTER TABLE " . table($TABLE);
$drop = "\nDROP " . ($jush == "sql" ? "FOREIGN KEY " : "CONSTRAINT ") . idf_escape($name); $result = ($name == "" || queries("$alter DROP " . (JUSH == "sql" ? "FOREIGN KEY " : "CONSTRAINT ") . idf_escape($name)));
if ($_POST["drop"]) { if (!$row["drop"]) {
query_redirect($alter . $drop, $location, $message); $result = queries("$alter ADD" . format_foreign_key($row));
} else {
query_redirect($alter . ($name != "" ? "$drop," : "") . "\nADD" . format_foreign_key($row), $location, $message);
$error = lang('Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.') . "<br>$error"; //! no partitioning
} }
} }
queries_redirect(
ME . "table=" . urlencode($TABLE),
($row["drop"] ? lang('Foreign key has been dropped.') : ($name != "" ? lang('Foreign key has been altered.') : lang('Foreign key has been created.'))),
$result
);
if (!$row["drop"]) {
$error = "$error<br>" . lang('Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.'); //! no partitioning
}
} }
page_header(lang('Foreign key'), $error, array("table" => $TABLE), h($TABLE)); page_header(lang('Foreign key'), $error, array("table" => $TABLE), h($TABLE));
@@ -57,15 +61,22 @@ if ($row["db"] != "") {
$connection->select_db($row["db"]); $connection->select_db($row["db"]);
} }
if ($row["ns"] != "") { if ($row["ns"] != "") {
$orig_schema = get_schema();
set_schema($row["ns"]); set_schema($row["ns"]);
} }
$referencable = array_keys(array_filter(table_status('', true), 'fk_support')); $referencable = array_keys(array_filter(table_status('', true), 'Adminer\fk_support'));
$target = array_keys(fields(in_array($row["table"], $referencable) ? $row["table"] : reset($referencable))); $target = array_keys(fields(in_array($row["table"], $referencable) ? $row["table"] : reset($referencable)));
$onchange = "this.form['change-js'].value = '1'; this.form.submit();"; $onchange = "this.form['change-js'].value = '1'; this.form.submit();";
echo "<p>" . lang('Target table') . ": " . html_select("table", $referencable, $row["table"], $onchange) . "\n"; echo "<p>" . lang('Target table') . ": " . html_select("table", $referencable, $row["table"], $onchange) . "\n";
if ($jush == "pgsql") { if (support("scheme")) {
echo lang('Schema') . ": " . html_select("ns", $adminer->schemas(), $row["ns"] != "" ? $row["ns"] : $_GET["ns"], $onchange); $schemas = array_filter($adminer->schemas(), function ($schema) {
} elseif ($jush != "sqlite") { return !preg_match('~^information_schema$~i', $schema);
});
echo lang('Schema') . ": " . html_select("ns", $schemas, $row["ns"] != "" ? $row["ns"] : $_GET["ns"], $onchange);
if ($row["ns"] != "") {
set_schema($orig_schema);
}
} elseif (JUSH != "sqlite") {
$dbs = array(); $dbs = array();
foreach ($adminer->databases() as $db) { foreach ($adminer->databases() as $db) {
if (!information_schema($db)) { if (!information_schema($db)) {
@@ -90,18 +101,20 @@ foreach ($row["source"] as $key => $val) {
?> ?>
</table> </table>
<p> <p>
<?php echo lang('ON DELETE'); ?>: <?php echo html_select("on_delete", array(-1 => "") + explode("|", $on_actions), $row["on_delete"]); ?> <?php echo lang('ON DELETE'); ?>: <?php echo html_select("on_delete", array(-1 => "") + explode("|", $driver->onActions), $row["on_delete"]); ?>
<?php echo lang('ON UPDATE'); ?>: <?php echo html_select("on_update", array(-1 => "") + explode("|", $on_actions), $row["on_update"]); ?> <?php echo lang('ON UPDATE'); ?>: <?php echo html_select("on_update", array(-1 => "") + explode("|", $driver->onActions), $row["on_update"]); ?>
<?php echo doc_link(array( <?php echo doc_link(array(
'sql' => "innodb-foreign-key-constraints.html", 'sql' => "innodb-foreign-key-constraints.html",
'mariadb' => "foreign-keys/", 'mariadb' => "foreign-keys/",
'pgsql' => "sql-createtable.html#SQL-CREATETABLE-REFERENCES", 'pgsql' => "sql-createtable.html#SQL-CREATETABLE-REFERENCES",
'mssql' => "ms174979.aspx", 'mssql' => "t-sql/statements/create-table-transact-sql",
'oracle' => "https://docs.oracle.com/cd/B19306_01/server.102/b14200/clauses002.htm#sthref2903", 'oracle' => "SQLRF01111",
)); ?> )); ?>
<p> <p>
<input type="submit" value="<?php echo lang('Save'); ?>"> <input type="submit" value="<?php echo lang('Save'); ?>">
<noscript><p><input type="submit" name="add" value="<?php echo lang('Add column'); ?>"></noscript> <noscript><p><input type="submit" name="add" value="<?php echo lang('Add column'); ?>"></noscript>
<?php if ($name != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $name)); ?><?php } ?> <?php if ($name != "") { ?>
<input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $name)); ?>
<?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>"> <input type="hidden" name="token" value="<?php echo $token; ?>">
</form> </form>

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
// any method change in this file should be transferred to editor/include/adminer.inc.php and plugins/plugin.php // any method change in this file should be transferred to editor/include/adminer.inc.php and plugins/plugin.php
class Adminer { class Adminer {
@@ -119,11 +121,11 @@ class Adminer {
function loginForm() { function loginForm() {
global $drivers; global $drivers;
echo "<table class='layout'>\n"; echo "<table class='layout'>\n";
echo $this->loginFormField('driver', '<tr><th>' . lang('System') . '<td>', html_select("auth[driver]", $drivers, DRIVER, "loginDriver(this);") . "\n"); 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">' . "\n"); echo $this->loginFormField('server', '<tr><th>' . lang('Server') . '<td>', '<input name="auth[server]" value="' . h(SERVER) . '" title="hostname[:port]" placeholder="localhost" autocapitalize="off">');
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('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">' . "\n"); 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">' . "\n"); echo $this->loginFormField('db', '<tr><th>' . lang('Database') . '<td>', '<input name="auth[db]" value="' . h($_GET["db"]) . '" autocapitalize="off">');
echo "</table>\n"; echo "</table>\n";
echo "<p><input type='submit' value='" . lang('Login') . "'>\n"; echo "<p><input type='submit' value='" . lang('Login') . "'>\n";
echo checkbox("auth[permanent]", 1, $_COOKIE["adminer_permanent"], lang('Permanent login')) . "\n"; echo checkbox("auth[permanent]", 1, $_COOKIE["adminer_permanent"], lang('Permanent login')) . "\n";
@@ -136,7 +138,7 @@ class Adminer {
* @return string * @return string
*/ */
function loginFormField($name, $heading, $value) { function loginFormField($name, $heading, $value) {
return $heading . $value; return $heading . $value . "\n";
} }
/** Authorize the user /** Authorize the user
@@ -174,14 +176,16 @@ class Adminer {
* @return null * @return null
*/ */
function selectLinks($tableStatus, $set = "") { function selectLinks($tableStatus, $set = "") {
global $jush, $driver; global $driver;
echo '<p class="links">'; echo '<p class="links">';
$links = array("select" => lang('Select data')); $links = array("select" => lang('Select data'));
if (support("table") || support("indexes")) { if (support("table") || support("indexes")) {
$links["table"] = lang('Show structure'); $links["table"] = lang('Show structure');
} }
$is_view = false;
if (support("table")) { if (support("table")) {
if (is_view($tableStatus)) { $is_view = is_view($tableStatus);
if ($is_view) {
$links["view"] = lang('Alter view'); $links["view"] = lang('Alter view');
} else { } else {
$links["create"] = lang('Alter table'); $links["create"] = lang('Alter table');
@@ -194,7 +198,7 @@ class Adminer {
foreach ($links as $key => $val) { foreach ($links as $key => $val) {
echo " <a href='" . h(ME) . "$key=" . urlencode($name) . ($key == "edit" ? $set : "") . "'" . bold(isset($_GET[$key])) . ">$val</a>"; echo " <a href='" . h(ME) . "$key=" . urlencode($name) . ($key == "edit" ? $set : "") . "'" . bold(isset($_GET[$key])) . ">$val</a>";
} }
echo doc_link(array($jush => $driver->tableHelp($name)), "?"); echo doc_link(array(JUSH => $driver->tableHelp($name, $is_view)), "?");
echo "\n"; echo "\n";
} }
@@ -230,7 +234,7 @@ class Adminer {
* @return string * @return string
*/ */
function selectQuery($query, $start, $failed = false) { function selectQuery($query, $start, $failed = false) {
global $jush, $driver; global $driver;
$return = "</p>\n"; // required for IE9 inline edit $return = "</p>\n"; // required for IE9 inline edit
if (!$failed && ($warnings = $driver->warnings())) { if (!$failed && ($warnings = $driver->warnings())) {
$id = "warnings"; $id = "warnings";
@@ -238,7 +242,7 @@ class Adminer {
. "$return<div id='$id' class='hidden'>\n$warnings</div>\n" . "$return<div id='$id' class='hidden'>\n$warnings</div>\n"
; ;
} }
return "<p><code class='jush-$jush'>" . h(str_replace("\n", " ", $query)) . "</code> <span class='time'>(" . format_time($start) . ")</span>" return "<p><code class='jush-" . JUSH . "'>" . h(str_replace("\n", " ", $query)) . "</code> <span class='time'>(" . format_time($start) . ")</span>"
. (support("sql") ? " <a href='" . h(ME) . "sql=" . urlencode($query) . "'>" . lang('Edit') . "</a>" : "") . (support("sql") ? " <a href='" . h(ME) . "sql=" . urlencode($query) . "'>" . lang('Edit') . "</a>" : "")
. $return . $return
; ;
@@ -309,10 +313,11 @@ class Adminer {
* @return null * @return null
*/ */
function tableStructurePrint($fields) { function tableStructurePrint($fields) {
global $structured_types; global $driver;
echo "<div class='scrollable'>\n"; echo "<div class='scrollable'>\n";
echo "<table class='nowrap odds'>\n"; echo "<table class='nowrap odds'>\n";
echo "<thead><tr><th>" . lang('Column') . "<td>" . lang('Type') . (support("comment") ? "<td>" . lang('Comment') : "") . "</thead>\n"; echo "<thead><tr><th>" . lang('Column') . "<td>" . lang('Type') . (support("comment") ? "<td>" . lang('Comment') : "") . "</thead>\n";
$structured_types = $driver->structuredTypes();
foreach ($fields as $field) { foreach ($fields as $field) {
echo "<tr><th>" . h($field["field"]); echo "<tr><th>" . h($field["field"]);
$type = h($field["full_type"]); $type = h($field["full_type"]);
@@ -322,7 +327,8 @@ class Adminer {
; ;
echo ($field["null"] ? " <i>NULL</i>" : ""); echo ($field["null"] ? " <i>NULL</i>" : "");
echo ($field["auto_increment"] ? " <i>" . lang('Auto Increment') . "</i>" : ""); echo ($field["auto_increment"] ? " <i>" . lang('Auto Increment') . "</i>" : "");
echo (isset($field["default"]) ? " <span title='" . lang('Default value') . "'>[<b>" . h($field["default"]) . "</b>]</span>" : ""); $default = h($field["default"]);
echo (isset($field["default"]) ? " <span title='" . lang('Default value') . "'>[<b>" . ($field["generated"] ? "<code class='jush-" . JUSH . "'>$default</code>" : $default) . "</b>]</span>" : "");
echo (support("comment") ? "<td>" . h($field["comment"]) : ""); echo (support("comment") ? "<td>" . h($field["comment"]) : "");
echo "\n"; echo "\n";
} }
@@ -356,7 +362,7 @@ class Adminer {
* @return null * @return null
*/ */
function selectColumnsPrint($select, $columns) { function selectColumnsPrint($select, $columns) {
global $functions, $grouping; global $driver;
print_fieldset("select", lang('Select'), $select); print_fieldset("select", lang('Select'), $select);
$i = 0; $i = 0;
$select[""] = array(); $select[""] = array();
@@ -368,8 +374,8 @@ class Adminer {
$val["col"], $val["col"],
($key !== "" ? "selectFieldChange" : "selectAddRow") ($key !== "" ? "selectFieldChange" : "selectAddRow")
); );
echo "<div>" . ($functions || $grouping ? "<select name='columns[$i][fun]'>" echo "<div>" . ($driver->functions || $driver->grouping ? "<select name='columns[$i][fun]'>"
. optionlist(array(-1 => "") + array_filter(array(lang('Functions') => $functions, lang('Aggregation') => $grouping)), $val["fun"]) . "</select>" . optionlist(array(-1 => "") + array_filter(array(lang('Functions') => $driver->functions, lang('Aggregation') => $driver->grouping)), $val["fun"]) . "</select>"
. on_help("getTarget(event).value && getTarget(event).value.replace(/ |\$/, '(') + ')'", 1) . on_help("getTarget(event).value && getTarget(event).value.replace(/ |\$/, '(') + ')'", 1)
. script("qsl('select').onchange = function () { helpClose();" . ($key !== "" ? "" : " qsl('select, input', this.parentNode).onchange();") . " };", "") . script("qsl('select').onchange = function () { helpClose();" . ($key !== "" ? "" : " qsl('select, input', this.parentNode).onchange();") . " };", "")
. "($column)" : $column) . "</div>\n"; . "($column)" : $column) . "</div>\n";
@@ -388,7 +394,7 @@ class Adminer {
print_fieldset("search", lang('Search'), $where); print_fieldset("search", lang('Search'), $where);
foreach ($indexes as $i => $index) { foreach ($indexes as $i => $index) {
if ($index["type"] == "FULLTEXT") { if ($index["type"] == "FULLTEXT") {
echo "<div>(<i>" . implode("</i>, <i>", array_map('h', $index["columns"])) . "</i>) AGAINST"; echo "<div>(<i>" . implode("</i>, <i>", array_map('Adminer\h', $index["columns"])) . "</i>) AGAINST";
echo " <input type='search' name='fulltext[$i]' value='" . h($_GET["fulltext"][$i]) . "'>"; echo " <input type='search' name='fulltext[$i]' value='" . h($_GET["fulltext"][$i]) . "'>";
echo script("qsl('input').oninput = selectFieldChange;", ""); echo script("qsl('input').oninput = selectFieldChange;", "");
echo checkbox("boolean[$i]", 1, isset($_GET["boolean"][$i]), "BOOL"); echo checkbox("boolean[$i]", 1, isset($_GET["boolean"][$i]), "BOOL");
@@ -510,16 +516,16 @@ class Adminer {
/** Process columns box in select /** Process columns box in select
* @param array selectable columns * @param array selectable columns
* @param array * @param array
* @return array [array(select_expressions), array(group_expressions)] * @return array [[select_expressions], [group_expressions]]
*/ */
function selectColumnsProcess($columns, $indexes) { function selectColumnsProcess($columns, $indexes) {
global $functions, $grouping; global $driver;
$select = array(); // select expressions, empty for * $select = array(); // select expressions, empty for *
$group = array(); // expressions without aggregation - will be used for GROUP BY if an aggregation function is used $group = array(); // expressions without aggregation - will be used for GROUP BY if an aggregation function is used
foreach ((array) $_GET["columns"] as $key => $val) { foreach ((array) $_GET["columns"] as $key => $val) {
if ($val["fun"] == "count" || ($val["col"] != "" && (!$val["fun"] || in_array($val["fun"], $functions) || in_array($val["fun"], $grouping)))) { if ($val["fun"] == "count" || ($val["col"] != "" && (!$val["fun"] || in_array($val["fun"], $driver->functions) || in_array($val["fun"], $driver->grouping)))) {
$select[$key] = apply_sql_function($val["fun"], ($val["col"] != "" ? idf_escape($val["col"]) : "*")); $select[$key] = apply_sql_function($val["fun"], ($val["col"] != "" ? idf_escape($val["col"]) : "*"));
if (!in_array($val["fun"], $grouping)) { if (!in_array($val["fun"], $driver->grouping)) {
$group[] = $select[$key]; $group[] = $select[$key];
} }
} }
@@ -537,7 +543,7 @@ class Adminer {
$return = array(); $return = array();
foreach ($indexes as $i => $index) { foreach ($indexes as $i => $index) {
if ($index["type"] == "FULLTEXT" && $_GET["fulltext"][$i] != "") { if ($index["type"] == "FULLTEXT" && $_GET["fulltext"][$i] != "") {
$return[] = "MATCH (" . implode(", ", array_map('idf_escape', $index["columns"])) . ") AGAINST (" . q($_GET["fulltext"][$i]) . (isset($_GET["boolean"][$i]) ? " IN BOOLEAN MODE" : "") . ")"; $return[] = "MATCH (" . implode(", ", array_map('Adminer\idf_escape', $index["columns"])) . ") AGAINST (" . q($_GET["fulltext"][$i]) . (isset($_GET["boolean"][$i]) ? " IN BOOLEAN MODE" : "") . ")";
} }
} }
foreach ((array) $_GET["where"] as $key => $val) { foreach ((array) $_GET["where"] as $key => $val) {
@@ -565,7 +571,8 @@ class Adminer {
// find anywhere // find anywhere
$cols = array(); $cols = array();
foreach ($fields as $name => $field) { foreach ($fields as $name => $field) {
if ((preg_match('~^[-\d.' . (preg_match('~IN$~', $val["op"]) ? ',' : '') . ']+$~', $val["val"]) || !preg_match('~' . number_type() . '|bit~', $field["type"])) if (
(preg_match('~^[-\d.' . (preg_match('~IN$~', $val["op"]) ? ',' : '') . ']+$~', $val["val"]) || !preg_match('~' . number_type() . '|bit~', $field["type"]))
&& (!preg_match("~[\x80-\xFF]~", $val["val"]) || preg_match('~char|text|enum|set~', $field["type"])) && (!preg_match("~[\x80-\xFF]~", $val["val"]) || preg_match('~char|text|enum|set~', $field["type"]))
&& (!preg_match('~date|timestamp~', $field["type"]) || preg_match('~^\d+-\d+-\d+~', $val["val"])) && (!preg_match('~date|timestamp~', $field["type"]) || preg_match('~^\d+-\d+-\d+~', $val["val"]))
) { ) {
@@ -639,7 +646,7 @@ class Adminer {
* @return string * @return string
*/ */
function messageQuery($query, $time, $failed = false) { function messageQuery($query, $time, $failed = false) {
global $jush, $driver; global $driver;
restart_session(); restart_session();
$history = &get_session("queries"); $history = &get_session("queries");
if (!$history[$_GET["db"]]) { if (!$history[$_GET["db"]]) {
@@ -656,7 +663,7 @@ class Adminer {
$return = "<a href='#$id' class='toggle'>" . lang('Warnings') . "</a>, $return<div id='$id' class='hidden'>\n$warnings</div>\n"; $return = "<a href='#$id' class='toggle'>" . lang('Warnings') . "</a>, $return<div id='$id' class='hidden'>\n$warnings</div>\n";
} }
return " <span class='time'>" . @date("H:i:s") . "</span>" // @ - time zone may be not set return " <span class='time'>" . @date("H:i:s") . "</span>" // @ - time zone may be not set
. " $return<div id='$sql_id' class='hidden'><pre><code class='jush-$jush'>" . shorten_utf8($query, 1000) . "</code></pre>" . " $return<div id='$sql_id' class='hidden'><pre><code class='jush-" . JUSH . "'>" . shorten_utf8($query, 1000) . "</code></pre>"
. ($time ? " <span class='time'>($time)</span>" : '') . ($time ? " <span class='time'>($time)</span>" : '')
. (support("sql") ? '<p><a href="' . h(str_replace("db=" . urlencode(DB), "db=" . urlencode($_GET["db"]), ME) . 'sql=&history=' . (count($history[$_GET["db"]]) - 1)) . '">' . lang('Edit') . '</a>' : '') . (support("sql") ? '<p><a href="' . h(str_replace("db=" . urlencode(DB), "db=" . urlencode($_GET["db"]), ME) . 'sql=&history=' . (count($history[$_GET["db"]]) - 1)) . '">' . lang('Edit') . '</a>' : '')
. '</div>' . '</div>'
@@ -678,10 +685,10 @@ class Adminer {
* @return array * @return array
*/ */
function editFunctions($field) { function editFunctions($field) {
global $edit_functions; global $driver;
$return = ($field["null"] ? "NULL/" : ""); $return = ($field["null"] ? "NULL/" : "");
$update = isset($_GET["select"]) || where($_GET); $update = isset($_GET["select"]) || where($_GET);
foreach ($edit_functions as $key => $functions) { foreach ($driver->editFunctions as $key => $functions) {
if (!$key || (!isset($_GET["call"]) && $update)) { // relative functions if (!$key || (!isset($_GET["call"]) && $update)) { // relative functions
foreach ($functions as $pattern => $val) { foreach ($functions as $pattern => $val) {
if (!$pattern || preg_match("~$pattern~", $field["type"])) { if (!$pattern || preg_match("~$pattern~", $field["type"])) {
@@ -769,7 +776,7 @@ class Adminer {
* @return array empty to disable export * @return array empty to disable export
*/ */
function dumpFormat() { function dumpFormat() {
return array('sql' => 'SQL', 'csv' => 'CSV,', 'csv;' => 'CSV;', 'tsv' => 'TSV'); return (support("dump") ? array('sql' => 'SQL') : array()) + array('csv' => 'CSV,', 'csv;' => 'CSV;', 'tsv' => 'TSV');
} }
/** Export database structure /** Export database structure
@@ -821,15 +828,25 @@ class Adminer {
* @return null prints data * @return null prints data
*/ */
function dumpData($table, $style, $query) { function dumpData($table, $style, $query) {
global $connection, $jush; global $connection;
if ($style) { if ($style) {
$max_packet = ($jush == "sqlite" ? 0 : 1048576); // default, minimum is 1024 $max_packet = (JUSH == "sqlite" ? 0 : 1048576); // default, minimum is 1024
$fields = array(); $fields = array();
$identity_insert = false;
if ($_POST["format"] == "sql") { if ($_POST["format"] == "sql") {
if ($style == "TRUNCATE+INSERT") { if ($style == "TRUNCATE+INSERT") {
echo truncate_sql($table) . ";\n"; echo truncate_sql($table) . ";\n";
} }
$fields = fields($table); $fields = fields($table);
if (JUSH == "mssql") {
foreach ($fields as $field) {
if ($field["auto_increment"]) {
echo "SET IDENTITY_INSERT " . table($table) . " ON;\n";
$identity_insert = true;
break;
}
}
}
} }
$result = $connection->query($query, 1); // 1 - MYSQLI_USE_RESULT //! enum and set as numbers $result = $connection->query($query, 1); // 1 - MYSQLI_USE_RESULT //! enum and set as numbers
if ($result) { if ($result) {
@@ -862,7 +879,7 @@ class Adminer {
dump_csv($row); dump_csv($row);
} else { } else {
if (!$insert) { if (!$insert) {
$insert = "INSERT INTO " . table($table) . " (" . implode(", ", array_map('idf_escape', $keys)) . ") VALUES"; $insert = "INSERT INTO " . table($table) . " (" . implode(", ", array_map('Adminer\idf_escape', $keys)) . ") VALUES";
} }
foreach ($row as $key => $val) { foreach ($row as $key => $val) {
if ($generated[$key]) { if ($generated[$key]) {
@@ -892,6 +909,9 @@ class Adminer {
} elseif ($_POST["format"] == "sql") { } elseif ($_POST["format"] == "sql") {
echo "-- " . str_replace("\n", " ", $connection->error) . "\n"; echo "-- " . str_replace("\n", " ", $connection->error) . "\n";
} }
if ($identity_insert) {
echo "SET IDENTITY_INSERT " . table($table) . " OFF;\n";
}
} }
} }
@@ -945,7 +965,7 @@ class Adminer {
* @return null * @return null
*/ */
function navigation($missing) { function navigation($missing) {
global $VERSION, $jush, $drivers, $connection; global $VERSION, $drivers, $connection;
?> ?>
<h1> <h1>
<?php echo $this->name(); ?> <?php echo $this->name(); ?>
@@ -984,7 +1004,7 @@ class Adminer {
echo script_src("../externals/jush/modules/jush-txt.js"); echo script_src("../externals/jush/modules/jush-txt.js");
echo script_src("../externals/jush/modules/jush-js.js"); echo script_src("../externals/jush/modules/jush-js.js");
if (support("sql")) { if (support("sql")) {
echo script_src("../externals/jush/modules/jush-$jush.js"); echo script_src("../externals/jush/modules/jush-" . JUSH . ".js");
?> ?>
<script<?php echo nonce(); ?>> <script<?php echo nonce(); ?>>
<?php <?php
@@ -993,9 +1013,9 @@ class Adminer {
foreach ($tables as $table => $type) { foreach ($tables as $table => $type) {
$links[] = preg_quote($table, '/'); $links[] = preg_quote($table, '/');
} }
echo "var jushLinks = { $jush: [ '" . js_escape(ME) . (support("table") ? "table=" : "select=") . "\$&', /\\b(" . implode("|", $links) . ")\\b/g ] };\n"; 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) { foreach (array("bac", "bra", "sqlite_quo", "mssql_bra") as $val) {
echo "jushLinks.$val = jushLinks.$jush;\n"; echo "jushLinks.$val = jushLinks." . JUSH . ";\n";
} }
} }
$server_info = $connection->server_info; $server_info = $connection->server_info;
@@ -1011,9 +1031,7 @@ bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '
$actions[] = "<a href='" . h(ME) . "sql='" . bold(isset($_GET["sql"]) && !isset($_GET["import"])) . ">" . lang('SQL command') . "</a>"; $actions[] = "<a href='" . h(ME) . "sql='" . bold(isset($_GET["sql"]) && !isset($_GET["import"])) . ">" . lang('SQL command') . "</a>";
$actions[] = "<a href='" . h(ME) . "import='" . bold(isset($_GET["import"])) . ">" . lang('Import') . "</a>"; $actions[] = "<a href='" . h(ME) . "import='" . bold(isset($_GET["import"])) . ">" . lang('Import') . "</a>";
} }
if (support("dump")) { $actions[] = "<a href='" . h(ME) . "dump=" . urlencode(isset($_GET["table"]) ? $_GET["table"] : $_GET["select"]) . "' id='dump'" . bold(isset($_GET["dump"])) . ">" . lang('Export') . "</a>";
$actions[] = "<a href='" . h(ME) . "dump=" . urlencode(isset($_GET["table"]) ? $_GET["table"] : $_GET["select"]) . "' id='dump'" . bold(isset($_GET["dump"])) . ">" . lang('Export') . "</a>";
}
} }
$in_db = $_GET["ns"] !== "" && !$missing && DB != ""; $in_db = $_GET["ns"] !== "" && !$missing && DB != "";
if ($in_db) { if ($in_db) {
@@ -1091,5 +1109,4 @@ bodyLoad('<?php echo (is_object($connection) ? preg_replace('~^(\d\.?\d).*~s', '
} }
echo "</ul>\n"; echo "</ul>\n";
} }
} }

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$connection = ''; $connection = '';
$has_token = $_SESSION["token"]; $has_token = $_SESSION["token"];
@@ -64,7 +66,8 @@ if ($auth) {
$permanent[$key] = "$key:" . base64_encode($private ? encrypt_string($password, $private) : ""); $permanent[$key] = "$key:" . base64_encode($private ? encrypt_string($password, $private) : "");
cookie("adminer_permanent", implode(" ", $permanent)); cookie("adminer_permanent", implode(" ", $permanent));
} }
if (count($_POST) == 1 // 1 - auth if (
count($_POST) == 1 // 1 - auth
|| DRIVER != $vendor || DRIVER != $vendor
|| SERVER != $server || SERVER != $server
|| $_GET["username"] !== $username // "0" == "00" || $_GET["username"] !== $username // "0" == "00"
@@ -130,7 +133,7 @@ function auth_error($error) {
$error = lang('Session support must be enabled.'); $error = lang('Session support must be enabled.');
} }
$params = session_get_cookie_params(); $params = session_get_cookie_params();
cookie("adminer_key", ($_COOKIE["adminer_key"] ? $_COOKIE["adminer_key"] : rand_string()), $params["lifetime"]); cookie("adminer_key", ($_COOKIE["adminer_key"] ?: rand_string()), $params["lifetime"]);
page_header(lang('Login'), $error, null); page_header(lang('Login'), $error, null);
echo "<form action='' method='post'>\n"; echo "<form action='' method='post'>\n";
echo "<div>"; echo "<div>";
@@ -144,10 +147,10 @@ function auth_error($error) {
exit; exit;
} }
if (isset($_GET["username"]) && !class_exists("Min_DB")) { if (isset($_GET["username"]) && !class_exists('Adminer\Db')) {
unset($_SESSION["pwds"][DRIVER]); unset($_SESSION["pwds"][DRIVER]);
unset_permanent(); unset_permanent();
page_header(lang('No extension'), lang('None of the supported PHP extensions (%s) are available.', implode(", ", $possible_drivers)), false); page_header(lang('No extension'), lang('None of the supported PHP extensions (%s) are available.', implode(", ", Driver::$possibleDrivers)), false);
page_footer("auth"); page_footer("auth");
exit; exit;
} }
@@ -161,7 +164,10 @@ if (isset($_GET["username"]) && is_string(get_password())) {
} }
check_invalid_login(); check_invalid_login();
$connection = connect(); $connection = connect();
$driver = new Min_Driver($connection); $driver = new Driver($connection);
if ($adminer->operators === null) {
$adminer->operators = $driver->operators;
}
} }
$login = null; $login = null;

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
include "../adminer/include/version.inc.php"; include "../adminer/include/version.inc.php";
include "../adminer/include/errors.inc.php"; include "../adminer/include/errors.inc.php";
include "../adminer/include/coverage.inc.php"; include "../adminer/include/coverage.inc.php";
@@ -33,7 +35,7 @@ if ($_GET["script"] == "version") {
exit; exit;
} }
global $adminer, $connection, $driver, $drivers, $edit_functions, $enum_length, $error, $functions, $grouping, $HTTPS, $inout, $jush, $LANG, $langs, $on_actions, $permanent, $structured_types, $has_token, $token, $translations, $types, $unsigned, $VERSION; // allows including Adminer inside a function global $adminer, $connection, $driver, $drivers, $error, $HTTPS, $LANG, $langs, $permanent, $has_token, $token, $translations, $VERSION; // allows including Adminer inside a function
if (!$_SERVER["REQUEST_URI"]) { // IIS 5 compatibility if (!$_SERVER["REQUEST_URI"]) { // IIS 5 compatibility
$_SERVER["REQUEST_URI"] = $_SERVER["ORIG_PATH_INFO"]; $_SERVER["REQUEST_URI"] = $_SERVER["ORIG_PATH_INFO"];
@@ -50,11 +52,7 @@ $HTTPS = ($_SERVER["HTTPS"] && strcasecmp($_SERVER["HTTPS"], "off")) || ini_bool
if (!defined("SID")) { if (!defined("SID")) {
session_cache_limiter(""); // to allow restarting session session_cache_limiter(""); // to allow restarting session
session_name("adminer_sid"); // use specific session name to get own namespace session_name("adminer_sid"); // use specific session name to get own namespace
$params = array(0, preg_replace('~\?.*~', '', $_SERVER["REQUEST_URI"]), "", $HTTPS); session_set_cookie_params(0, preg_replace('~\?.*~', '', $_SERVER["REQUEST_URI"]), "", $HTTPS, true); // ini_set() may be disabled
if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
$params[] = true; // HttpOnly
}
call_user_func_array('session_set_cookie_params', $params); // ini_set() may be disabled
session_start(); session_start();
} }
@@ -80,27 +78,16 @@ include "./include/adminer.inc.php";
$adminer = (function_exists('adminer_object') ? adminer_object() : new Adminer); $adminer = (function_exists('adminer_object') ? adminer_object() : new Adminer);
include "../adminer/drivers/mysql.inc.php"; // must be included as last driver include "../adminer/drivers/mysql.inc.php"; // must be included as last driver
$config = driver_config(); define('Adminer\JUSH', Driver::$jush);
$possible_drivers = $config['possible_drivers']; define('Adminer\SERVER', $_GET[DRIVER]); // read from pgsql=localhost
$jush = $config['jush']; define('Adminer\DB', $_GET["db"]); // for the sake of speed and size
$types = $config['types']; define(
$structured_types = $config['structured_types']; 'Adminer\ME',
$unsigned = $config['unsigned']; preg_replace('~\?.*~', '', relative_uri()) . '?'
$operators = $config['operators']; . (sid() ? SID . '&' : '')
$functions = $config['functions']; . (SERVER !== null ? DRIVER . "=" . urlencode(SERVER) . '&' : '')
$grouping = $config['grouping']; . (isset($_GET["username"]) ? "username=" . urlencode($_GET["username"]) . '&' : '')
$edit_functions = $config['edit_functions']; . (DB != "" ? 'db=' . urlencode(DB) . '&' . (isset($_GET["ns"]) ? "ns=" . urlencode($_GET["ns"]) . "&" : "") : '')
if ($adminer->operators === null) {
$adminer->operators = $operators;
}
define("SERVER", $_GET[DRIVER]); // read from pgsql=localhost
define("DB", $_GET["db"]); // for the sake of speed and size
define("ME", preg_replace('~\?.*~', '', relative_uri()) . '?'
. (sid() ? SID . '&' : '')
. (SERVER !== null ? DRIVER . "=" . urlencode(SERVER) . '&' : '')
. (isset($_GET["username"]) ? "username=" . urlencode($_GET["username"]) . '&' : '')
. (DB != "" ? 'db=' . urlencode(DB) . '&' . (isset($_GET["ns"]) ? "ns=" . urlencode($_GET["ns"]) . "&" : "") : '')
); );
include "../adminer/include/design.inc.php"; include "../adminer/include/design.inc.php";
@@ -108,5 +95,3 @@ include "../adminer/include/xxtea.inc.php";
include "../adminer/include/auth.inc.php"; include "../adminer/include/auth.inc.php";
include "./include/editing.inc.php"; include "./include/editing.inc.php";
include "./include/connect.inc.php"; include "./include/connect.inc.php";
$on_actions = "RESTRICT|NO ACTION|CASCADE|SET NULL|SET DEFAULT"; ///< @var string used in foreign_keys()

View File

@@ -1,6 +1,18 @@
<?php <?php
function connect_error() { namespace Adminer;
global $adminer, $connection, $token, $error, $drivers;
if (isset($_GET["status"])) {
$_GET["variables"] = $_GET["status"];
}
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 != "" || $_GET["refresh"]) {
restart_session();
set_session("dbs", null);
}
if (DB != "") { if (DB != "") {
header("HTTP/1.1 404 Not Found"); header("HTTP/1.1 404 Not Found");
page_header(lang('Database') . ": " . h(DB), lang('Invalid database.'), true); page_header(lang('Database') . ": " . h(DB), lang('Invalid database.'), true);
@@ -11,13 +23,15 @@ function connect_error() {
page_header(lang('Select database'), $error, false); page_header(lang('Select database'), $error, false);
echo "<p class='links'>\n"; echo "<p class='links'>\n";
foreach (array( foreach (
'database' => lang('Create database'), array(
'privileges' => lang('Privileges'), 'database' => lang('Create database'),
'processlist' => lang('Process list'), 'privileges' => lang('Privileges'),
'variables' => lang('Variables'), 'processlist' => lang('Process list'),
'status' => lang('Status'), 'variables' => lang('Variables'),
) as $key => $val) { 'status' => lang('Status'),
) as $key => $val
) {
if (support($key)) { if (support($key)) {
echo "<a href='" . h(ME) . "$key='>$val</a>\n"; echo "<a href='" . h(ME) . "$key='>$val</a>\n";
} }
@@ -33,7 +47,7 @@ function connect_error() {
echo script("mixin(qsl('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true)});"); echo script("mixin(qsl('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true)});");
echo "<thead><tr>" echo "<thead><tr>"
. (support("database") ? "<td>" : "") . (support("database") ? "<td>" : "")
. "<th>" . lang('Database') . " - <a href='" . h(ME) . "refresh=1'>" . lang('Refresh') . "</a>" . "<th>" . lang('Database') . (get_session("dbs") !== null ? " - <a href='" . h(ME) . "refresh=1'>" . lang('Refresh') . "</a>" : "")
. "<td>" . lang('Collation') . "<td>" . lang('Collation')
. "<td>" . lang('Tables') . "<td>" . lang('Tables')
. "<td>" . lang('Size') . " - <a href='" . h(ME) . "dbsize=1'>" . lang('Compute') . "</a>" . script("qsl('a').onclick = partial(ajaxSetHtml, '" . js_escape(ME) . "script=connect');", "") . "<td>" . lang('Size') . " - <a href='" . h(ME) . "dbsize=1'>" . lang('Compute') . "</a>" . script("qsl('a').onclick = partial(ajaxSetHtml, '" . js_escape(ME) . "script=connect');", "")
@@ -71,21 +85,6 @@ function connect_error() {
} }
page_footer("db"); page_footer("db");
}
if (isset($_GET["status"])) {
$_GET["variables"] = $_GET["status"];
}
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 != "" || $_GET["refresh"]) {
restart_session();
set_session("dbs", null);
}
connect_error(); // separate function to catch SQLite error
exit; exit;
} }

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
// coverage is used in tests and removed in compilation // 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.ser")) {
function save_coverage() { function save_coverage() {
@@ -14,5 +16,5 @@ if (extension_loaded("xdebug") && file_exists(sys_get_temp_dir() . "/adminer_cov
} }
} }
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE); xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
register_shutdown_function('save_coverage'); register_shutdown_function('Adminer\save_coverage');
} }

View File

@@ -1,13 +1,19 @@
<?php <?php
namespace Adminer;
if (!ob_get_level()) {
ob_start(null, 4096);
}
/** Print HTML header /** Print HTML header
* @param string used in title, breadcrumb and heading, should be HTML escaped * @param string used in title, breadcrumb and heading, should be HTML escaped
* @param string * @param string
* @param mixed array("key" => "link", "key2" => array("link", "desc")), null for nothing, false for driver only, true for driver and server * @param mixed ["key" => "link", "key2" => ["link", "desc"]], null for nothing, false for driver only, true for driver and server
* @param string used after colon in title and heading, should be HTML escaped * @param string used after colon in title and heading, should be HTML escaped
* @return null * @return null
*/ */
function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") { function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") {
global $LANG, $VERSION, $adminer, $drivers, $jush; global $LANG, $VERSION, $adminer, $drivers;
page_headers(); page_headers();
if (is_ajax() && $error) { if (is_ajax() && $error) {
page_messages($error); page_messages($error);
@@ -62,14 +68,14 @@ var offlineMessage = '<?php echo js_escape(lang('You are offline.')); ?>';
var thousandsSeparator = '<?php echo js_escape(lang(',')); ?>'; var thousandsSeparator = '<?php echo js_escape(lang(',')); ?>';
</script> </script>
<div id="help" class="jush-<?php echo $jush; ?> jsonly hidden"></div> <div id="help" class="jush-<?php echo JUSH; ?> jsonly hidden"></div>
<?php echo script("mixin(qs('#help'), {onmouseover: function () { helpOpen = 1; }, onmouseout: helpMouseout});"); ?> <?php echo script("mixin(qs('#help'), {onmouseover: function () { helpOpen = 1; }, onmouseout: helpMouseout});"); ?>
<div id="content"> <div id="content">
<?php <?php
if ($breadcrumb !== null) { if ($breadcrumb !== null) {
$link = substr(preg_replace('~\b(username|db|ns)=[^&]*&~', '', ME), 0, -1); $link = substr(preg_replace('~\b(username|db|ns)=[^&]*&~', '', ME), 0, -1);
echo '<p id="breadcrumb"><a href="' . h($link ? $link : ".") . '">' . $drivers[DRIVER] . '</a> » '; echo '<p id="breadcrumb"><a href="' . h($link ?: ".") . '">' . $drivers[DRIVER] . '</a> » ';
$link = substr(preg_replace('~\b(db|ns)=[^&]*&~', '', ME), 0, -1); $link = substr(preg_replace('~\b(db|ns)=[^&]*&~', '', ME), 0, -1);
$server = $adminer->serverName(SERVER); $server = $adminer->serverName(SERVER);
$server = ($server != "" ? $server : lang('Server')); $server = ($server != "" ? $server : lang('Server'));
@@ -103,7 +109,7 @@ var thousandsSeparator = '<?php echo js_escape(lang(',')); ?>';
$databases = null; $databases = null;
} }
stop_session(); stop_session();
define("PAGE_HEADER", 1); define('Adminer\PAGE_HEADER', 1);
} }
/** Send HTTP headers /** Send HTTP headers

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$drivers = array(); $drivers = array();
/** Add a driver /** Add a driver
@@ -20,16 +22,43 @@ function get_driver($id) {
return $drivers[$id]; return $drivers[$id];
} }
/*abstract*/ class Min_SQL { abstract class SqlDriver {
static $possibleDrivers = array();
static $jush; ///< @var string JUSH identifier
var $_conn; var $_conn;
protected $types = array(); ///< @var array [$description => [$type => $maximum_unsigned_length, ...], ...]
var $editFunctions = array(); ///< @var array of ["$type|$type2" => "$function/$function2"] functions used in editing, [0] - edit and insert, [1] - edit only
var $unsigned = array(); ///< @var array number variants
var $operators = array(); ///< @var array operators used in select
var $functions = array(); ///< @var array functions used in select
var $grouping = array(); ///< @var array grouping functions used in select
var $onActions = "RESTRICT|NO ACTION|CASCADE|SET NULL|SET DEFAULT"; ///< @var string used in foreign_keys()
var $inout = "IN|OUT|INOUT";
var $enumLength = "'(?:''|[^'\\\\]|\\\\.)*'";
var $generated = array();
/** Create object for performing database operations /** Create object for performing database operations
* @param Min_DB * @param Db
*/ */
function __construct($connection) { function __construct($connection) {
$this->_conn = $connection; $this->_conn = $connection;
} }
/** Get all types
* @return array [$type => $maximum_unsigned_length, ...]
*/
function types() {
return call_user_func_array('array_merge', array_values($this->types));
}
/** Get structured types
* @return array [$description => [$type, ...], ...]
*/
function structuredTypes() {
return array_map('array_keys', $this->types);
}
/** Select data from table /** Select data from table
* @param string * @param string
* @param array result of $adminer->selectColumnsProcess()[0] * @param array result of $adminer->selectColumnsProcess()[0]
@@ -39,15 +68,15 @@ function get_driver($id) {
* @param int result of $adminer->selectLimitProcess() * @param int result of $adminer->selectLimitProcess()
* @param int index of page starting at zero * @param int index of page starting at zero
* @param bool whether to print the query * @param bool whether to print the query
* @return Min_Result * @return Result
*/ */
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) { function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
global $adminer, $jush; global $adminer;
$is_group = (count($group) < count($select)); $is_group = (count($group) < count($select));
$query = $adminer->selectQueryBuild($select, $where, $group, $order, $limit, $page); $query = $adminer->selectQueryBuild($select, $where, $group, $order, $limit, $page);
if (!$query) { if (!$query) {
$query = "SELECT" . limit( $query = "SELECT" . limit(
($_GET["page"] != "last" && $limit != "" && $group && $is_group && $jush == "sql" ? "SQL_CALC_FOUND_ROWS " : "") . implode(", ", $select) . "\nFROM " . table($table), ($_GET["page"] != "last" && $limit != "" && $group && $is_group && JUSH == "sql" ? "SQL_CALC_FOUND_ROWS " : "") . implode(", ", $select) . "\nFROM " . table($table),
($where ? "\nWHERE " . implode(" AND ", $where) : "") . ($group && $is_group ? "\nGROUP BY " . implode(", ", $group) : "") . ($order ? "\nORDER BY " . implode(", ", $order) : ""), ($where ? "\nWHERE " . implode(" AND ", $where) : "") . ($group && $is_group ? "\nGROUP BY " . implode(", ", $group) : "") . ($order ? "\nORDER BY " . implode(", ", $order) : ""),
($limit != "" ? +$limit : null), ($limit != "" ? +$limit : null),
($page ? $limit * $page : 0), ($page ? $limit * $page : 0),
@@ -108,7 +137,7 @@ function get_driver($id) {
* @param array of arrays with escaped columns in keys and quoted data in values * @param array of arrays with escaped columns in keys and quoted data in values
* @return bool * @return bool
*/ */
/*abstract*/ function insertUpdate($table, $rows, $primary) { function insertUpdate($table, $rows, $primary) {
return false; return false;
} }
@@ -188,9 +217,30 @@ function get_driver($id) {
/** Get help link for table /** Get help link for table
* @param string * @param string
* @param bool
* @return string relative URL or null * @return string relative URL or null
*/ */
function tableHelp($name) { function tableHelp($name, $is_view = false) {
} }
/** Check if C-style escapes are supported
* @return bool
*/
function hasCStyleEscapes() {
return false;
}
/** Get defined check constraints
* @param string
* @return array [$name => $clause]
*/
function checkConstraints($table) {
// MariaDB contains CHECK_CONSTRAINTS.TABLE_NAME, MySQL and PostrgreSQL not
return get_key_vals("SELECT c.CONSTRAINT_NAME, CHECK_CLAUSE
FROM INFORMATION_SCHEMA.CHECK_CONSTRAINTS c
JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS t ON c.CONSTRAINT_SCHEMA = t.CONSTRAINT_SCHEMA AND c.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE c.CONSTRAINT_SCHEMA = " . q($_GET["ns"] != "" ? $_GET["ns"] : DB) . "
AND t.TABLE_NAME = " . q($table) . "
AND CHECK_CLAUSE NOT LIKE '% IS NOT NULL'"); // ignore default IS NOT NULL checks in PostrgreSQL
}
} }

View File

@@ -1,15 +1,16 @@
<?php <?php
namespace Adminer;
// This file is not used in Adminer Editor. // This file is not used in Adminer Editor.
/** Print select result /** Print select result
* @param Min_Result * @param Result
* @param Min_DB connection to examine indexes * @param Db connection to examine indexes
* @param array * @param array
* @param int * @param int
* @return array $orgtables * @return array $orgtables
*/ */
function select($result, $connection2 = null, $orgtables = array(), $limit = 0) { function select($result, $connection2 = null, $orgtables = array(), $limit = 0) {
global $jush;
$links = array(); // colno => orgtable - create links from these columns $links = array(); // colno => orgtable - create links from these columns
$indexes = array(); // orgtable => array(column => colno) - primary keys $indexes = array(); // orgtable => array(column => colno) - primary keys
$columns = array(); // orgtable => array(column => ) - not selected columns in primary key $columns = array(); // orgtable => array(column => ) - not selected columns in primary key
@@ -27,7 +28,7 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
$orgtable = $field->orgtable; $orgtable = $field->orgtable;
$orgname = $field->orgname; $orgname = $field->orgname;
$return[$field->table] = $orgtable; $return[$field->table] = $orgtable;
if ($orgtables && $jush == "sql") { // MySQL EXPLAIN if ($orgtables && JUSH == "sql") { // MySQL EXPLAIN
$links[$j] = ($name == "table" ? "table=" : ($name == "possible_keys" ? "indexes=" : null)); $links[$j] = ($name == "table" ? "table=" : ($name == "possible_keys" ? "indexes=" : null));
} elseif ($orgtable != "") { } elseif ($orgtable != "") {
if (!isset($indexes[$orgtable])) { if (!isset($indexes[$orgtable])) {
@@ -64,7 +65,7 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
foreach ($row as $key => $val) { foreach ($row as $key => $val) {
$link = ""; $link = "";
if (isset($links[$key]) && !$columns[$links[$key]]) { if (isset($links[$key]) && !$columns[$links[$key]]) {
if ($orgtables && $jush == "sql") { // MySQL EXPLAIN if ($orgtables && JUSH == "sql") { // MySQL EXPLAIN
$table = $row[array_search("table=", $links)]; $table = $row[array_search("table=", $links)];
$link = ME . $links[$key] . urlencode($orgtables[$table] != "" ? $orgtables[$table] : $table); $link = ME . $links[$key] . urlencode($orgtables[$table] != "" ? $orgtables[$table] : $table);
} else { } else {
@@ -151,8 +152,7 @@ function set_adminer_settings($settings) {
* @return null * @return null
*/ */
function textarea($name, $value, $rows = 10, $cols = 80) { function textarea($name, $value, $rows = 10, $cols = 80) {
global $jush; echo "<textarea name='" . h($name) . "' rows='$rows' cols='$cols' class='sqlarea jush-" . JUSH . "' spellcheck='false' wrap='off'>";
echo "<textarea name='" . h($name) . "' rows='$rows' cols='$cols' class='sqlarea jush-$jush' spellcheck='false' wrap='off'>";
if (is_array($value)) { if (is_array($value)) {
foreach ($value as $val) { // not implode() to save memory foreach ($value as $val) { // not implode() to save memory
echo h($val[0]) . "\n\n\n"; // $val == array($query, $time, $elapsed) echo h($val[0]) . "\n\n\n"; // $val == array($query, $time, $elapsed)
@@ -207,12 +207,13 @@ function json_row($key, $val = null) {
* @return null * @return null
*/ */
function edit_type($key, $field, $collations, $foreign_keys = array(), $extra_types = array()) { function edit_type($key, $field, $collations, $foreign_keys = array(), $extra_types = array()) {
global $structured_types, $types, $unsigned, $on_actions; global $driver;
$type = $field["type"]; $type = $field["type"];
?><td><select name="<?php echo h($key); ?>[type]" class="type" aria-labelledby="label-type"><?php ?><td><select name="<?php echo h($key); ?>[type]" class="type" aria-labelledby="label-type"><?php
if ($type && !isset($types[$type]) && !isset($foreign_keys[$type]) && !in_array($type, $extra_types)) { if ($type && !array_key_exists($type, $driver->types()) && !isset($foreign_keys[$type]) && !in_array($type, $extra_types)) {
$extra_types[] = $type; $extra_types[] = $type;
} }
$structured_types = $driver->structuredTypes();
if ($foreign_keys) { if ($foreign_keys) {
$structured_types[lang('Foreign keys')] = $foreign_keys; $structured_types[lang('Foreign keys')] = $foreign_keys;
} }
@@ -224,12 +225,12 @@ function edit_type($key, $field, $collations, $foreign_keys = array(), $extra_ty
<?php echo (!$field["length"] && preg_match('~var(char|binary)$~', $type) ? " class='required'" : ""); //! type="number" with enabled JavaScript ?> <?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 aria-labelledby="label-length"><td class="options"><?php
echo ($collations ? "<select name='" . h($key) . "[collation]'" . (preg_match('~(char|text|enum|set)$~', $type) ? "" : " class='hidden'") . '><option value="">(' . lang('collation') . ')' . optionlist($collations, $field["collation"]) . '</select>' : ''); echo ($collations ? "<select name='" . h($key) . "[collation]'" . (preg_match('~(char|text|enum|set)$~', $type) ? "" : " class='hidden'") . '><option value="">(' . lang('collation') . ')' . optionlist($collations, $field["collation"]) . '</select>' : '');
echo ($unsigned ? "<select name='" . h($key) . "[unsigned]'" . (!$type || preg_match(number_type(), $type) ? "" : " class='hidden'") . '><option>' . optionlist($unsigned, $field["unsigned"]) . '</select>' : ''); 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'") . '>' 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"])) . optionlist(array("" => "(" . lang('ON UPDATE') . ")", "CURRENT_TIMESTAMP"), (preg_match('~^CURRENT_TIMESTAMP~i', $field["on_update"]) ? "CURRENT_TIMESTAMP" : $field["on_update"]))
. '</select>' : '' . '</select>' : ''
); );
echo ($foreign_keys ? "<select name='" . h($key) . "[on_delete]'" . (preg_match("~`~", $type) ? "" : " class='hidden'") . "><option value=''>(" . lang('ON DELETE') . ")" . optionlist(explode("|", $on_actions), $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 /** Get partition info
@@ -253,7 +254,8 @@ function get_partitions_info($table) {
* @return string * @return string
*/ */
function process_length($length) { function process_length($length) {
global $enum_length; global $driver;
$enum_length = $driver->enumLength;
return (preg_match("~^\\s*\\(?\\s*$enum_length(?:\\s*,\\s*$enum_length)*+\\s*\\)?\\s*\$~", $length) && preg_match_all("~$enum_length~", $length, $matches) return (preg_match("~^\\s*\\(?\\s*$enum_length(?:\\s*,\\s*$enum_length)*+\\s*\\)?\\s*\$~", $length) && preg_match_all("~$enum_length~", $length, $matches)
? "(" . implode(",", $matches[0]) . ")" ? "(" . implode(",", $matches[0]) . ")"
: preg_replace('~^[0-9].*~', '(\0)', preg_replace('~[^-0-9,+()[\]]~', '', $length)) : preg_replace('~^[0-9].*~', '(\0)', preg_replace('~[^-0-9,+()[\]]~', '', $length))
@@ -266,11 +268,11 @@ function process_length($length) {
* @return string * @return string
*/ */
function process_type($field, $collate = "COLLATE") { function process_type($field, $collate = "COLLATE") {
global $unsigned; global $driver;
return " $field[type]" return " $field[type]"
. process_length($field["length"]) . process_length($field["length"])
. (preg_match(number_type(), $field["type"]) && in_array($field["unsigned"], $unsigned) ? " $field[unsigned]" : "") . (preg_match(number_type(), $field["type"]) && in_array($field["unsigned"], $driver->unsigned) ? " $field[unsigned]" : "")
. (preg_match('~char|text|enum|set~', $field["type"]) && $field["collation"] ? " $collate " . q($field["collation"]) : "") . (preg_match('~char|text|enum|set~', $field["type"]) && $field["collation"] ? " $collate " . (JUSH == "mssql" ? $field["collation"] : q($field["collation"])) : "")
; ;
} }
@@ -300,12 +302,16 @@ function process_field($field, $type_field) {
* @return string * @return string
*/ */
function default_value($field) { function default_value($field) {
global $jush; global $driver;
$default = $field["default"]; $default = $field["default"];
return ($default === null ? "" : " DEFAULT " . $generated = $field["generated"];
(!preg_match('~^GENERATED ~i', $default) && (preg_match('~char|binary|text|enum|set~', $field["type"]) || preg_match('~^(?![a-z])~i', $default)) return ($default === null ? "" : (in_array($generated, $driver->generated)
? q($default) : str_ireplace("current_timestamp()", "CURRENT_TIMESTAMP", ($jush == "sqlite" ? "($default)" : $default))) ? (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))
? q($default)
: str_ireplace("current_timestamp()", "CURRENT_TIMESTAMP", (JUSH == "sqlite" ? "($default)" : $default))
)
));
} }
/** Get type class to use in CSS /** Get type class to use in CSS
@@ -313,12 +319,14 @@ function default_value($field) {
* @return string class='' * @return string class=''
*/ */
function type_class($type) { function type_class($type) {
foreach (array( foreach (
'char' => 'text', array(
'date' => 'time|year', 'char' => 'text',
'binary' => 'blob', 'date' => 'time|year',
'enum' => 'set', 'binary' => 'blob',
) as $key => $val) { 'enum' => 'set',
) as $key => $val
) {
if (preg_match("~$key|$val~", $type)) { if (preg_match("~$key|$val~", $type)) {
return " class='$key'"; return " class='$key'";
} }
@@ -333,13 +341,13 @@ function type_class($type) {
* @return null * @return null
*/ */
function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = array()) { function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = array()) {
global $inout; global $driver;
$fields = array_values($fields); $fields = array_values($fields);
$default_class = (($_POST ? $_POST["defaults"] : adminer_setting("defaults")) ? "" : " class='hidden'"); $default_class = (($_POST ? $_POST["defaults"] : adminer_setting("defaults")) ? "" : " class='hidden'");
$comment_class = (($_POST ? $_POST["comments"] : adminer_setting("comments")) ? "" : " class='hidden'"); $comment_class = (($_POST ? $_POST["comments"] : adminer_setting("comments")) ? "" : " class='hidden'");
?> ?>
<thead><tr> <thead><tr>
<?php if ($type == "PROCEDURE") { ?><td><?php } ?> <?php echo ($type == "PROCEDURE" ? "<td>" : ""); ?>
<th id="label-name"><?php echo ($type == "TABLE" ? lang('Column name') : lang('Parameter name')); ?> <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-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 id="label-length"><?php echo lang('Length'); ?>
@@ -351,7 +359,7 @@ function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = arra
'mariadb' => "auto_increment/", 'mariadb' => "auto_increment/",
'sqlite' => "autoinc.html", 'sqlite' => "autoinc.html",
'pgsql' => "datatype-numeric.html#DATATYPE-SERIAL", 'pgsql' => "datatype-numeric.html#DATATYPE-SERIAL",
'mssql' => "ms186775.aspx", 'mssql' => "t-sql/statements/create-table-transact-sql-identity-property",
)); ?> )); ?>
<td id="label-default"<?php echo $default_class; ?>><?php echo lang('Default value'); ?> <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 echo (support("comment") ? "<td id='label-comment'$comment_class>" . lang('Comment') : ""); ?>
@@ -367,13 +375,22 @@ function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = arra
$display = (isset($_POST["add"][$i-1]) || (isset($field["field"]) && !$_POST["drop_col"][$i])) && (support("drop_col") || $orig == ""); $display = (isset($_POST["add"][$i-1]) || (isset($field["field"]) && !$_POST["drop_col"][$i])) && (support("drop_col") || $orig == "");
?> ?>
<tr<?php echo ($display ? "" : " style='display: none;'"); ?>> <tr<?php echo ($display ? "" : " style='display: none;'"); ?>>
<?php echo ($type == "PROCEDURE" ? "<td>" . html_select("fields[$i][inout]", explode("|", $inout), $field["inout"]) : ""); ?> <?php echo ($type == "PROCEDURE" ? "<td>" . html_select("fields[$i][inout]", explode("|", $driver->inout), $field["inout"]) : "") . "<th>"; ?>
<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 } ?> <?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); ?> <input type="hidden" name="fields[<?php echo $i; ?>][orig]" value="<?php echo h($orig); ?>"><?php edit_type("fields[$i]", $field, $collations, $foreign_keys); ?>
<?php if ($type == "TABLE") { ?> <?php
if ($type == "TABLE") {
?>
<td><?php echo checkbox("fields[$i][null]", 1, $field["null"], "", "", "block", "label-null"); ?> <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 if ($field["auto_increment"]) { ?> checked<?php } ?> aria-labelledby="label-ai"></label><td<?php echo $default_class; ?>><?php <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 checkbox("fields[$i][has_default]", 1, $field["has_default"], "", "", "", "label-default"); ?><input name="fields[<?php echo $i; ?>][default]" value="<?php echo h($field["default"]); ?>" aria-labelledby="label-default"><?php echo ($driver->generated
? "<select name='fields[$i][generated]'>" . optionlist(array_merge(array("", "DEFAULT"), $driver->generated), $field["generated"]) . "</select> "
: 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 (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 (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>"; echo "<td>";
@@ -496,11 +513,10 @@ function drop_create($drop, $create, $drop_created, $test, $drop_test, $location
* @return string * @return string
*/ */
function create_trigger($on, $row) { function create_trigger($on, $row) {
global $jush;
$timing_event = " $row[Timing] $row[Event]" . (preg_match('~ OF~', $row["Event"]) ? " $row[Of]" : ""); // SQL injection $timing_event = " $row[Timing] $row[Event]" . (preg_match('~ OF~', $row["Event"]) ? " $row[Of]" : ""); // SQL injection
return "CREATE TRIGGER " return "CREATE TRIGGER "
. idf_escape($row["Trigger"]) . idf_escape($row["Trigger"])
. ($jush == "mssql" ? $on . $timing_event : $timing_event . $on) . (JUSH == "mssql" ? $on . $timing_event : $timing_event . $on)
. rtrim(" $row[Type]\n$row[Statement]", ";") . rtrim(" $row[Type]\n$row[Statement]", ";")
. ";" . ";"
; ;
@@ -512,13 +528,13 @@ function create_trigger($on, $row) {
* @return string * @return string
*/ */
function create_routine($routine, $row) { function create_routine($routine, $row) {
global $inout, $jush; global $driver;
$set = array(); $set = array();
$fields = (array) $row["fields"]; $fields = (array) $row["fields"];
ksort($fields); // enforce fields order ksort($fields); // enforce fields order
foreach ($fields as $field) { foreach ($fields as $field) {
if ($field["field"] != "") { if ($field["field"] != "") {
$set[] = (preg_match("~^($inout)\$~", $field["inout"]) ? "$field[inout] " : "") . idf_escape($field["field"]) . process_type($field, "CHARACTER SET"); $set[] = (preg_match("~^($driver->inout)\$~", $field["inout"]) ? "$field[inout] " : "") . idf_escape($field["field"]) . process_type($field, "CHARACTER SET");
} }
} }
$definition = rtrim($row["definition"], ";"); $definition = rtrim($row["definition"], ";");
@@ -527,24 +543,10 @@ function create_routine($routine, $row) {
. " (" . implode(", ", $set) . ")" . " (" . implode(", ", $set) . ")"
. ($routine == "FUNCTION" ? " RETURNS" . process_type($row["returns"], "CHARACTER SET") : "") . ($routine == "FUNCTION" ? " RETURNS" . process_type($row["returns"], "CHARACTER SET") : "")
. ($row["language"] ? " LANGUAGE $row[language]" : "") . ($row["language"] ? " LANGUAGE $row[language]" : "")
. ($jush == "pgsql" ? " AS " . q($definition) : "\n$definition;") . (JUSH == "pgsql" ? " AS " . q($definition) : "\n$definition;")
; ;
} }
/** Get defined check constraints
* @param string
* @return array [$name => $clause]
*/
function check_constraints($table) {
// MariaDB contains CHECK_CONSTRAINTS.TABLE_NAME, MySQL and PostrgreSQL not
return get_key_vals("SELECT c.CONSTRAINT_NAME, CHECK_CLAUSE
FROM INFORMATION_SCHEMA.CHECK_CONSTRAINTS c
JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS t ON c.CONSTRAINT_SCHEMA = t.CONSTRAINT_SCHEMA AND c.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE c.CONSTRAINT_SCHEMA = " . q($_GET["ns"] != "" ? $_GET["ns"] : DB) . "
AND t.TABLE_NAME = " . q($table) . "
AND CHECK_CLAUSE NOT LIKE '% IS NOT NULL'"); // ignore default IS NOT NULL checks in PostrgreSQL
}
/** Remove current user definer from SQL command /** Remove current user definer from SQL command
* @param string * @param string
* @return string * @return string
@@ -558,16 +560,16 @@ function remove_definer($query) {
* @return string * @return string
*/ */
function format_foreign_key($foreign_key) { function format_foreign_key($foreign_key) {
global $on_actions; global $driver;
$db = $foreign_key["db"]; $db = $foreign_key["db"];
$ns = $foreign_key["ns"]; $ns = $foreign_key["ns"];
return " FOREIGN KEY (" . implode(", ", array_map('idf_escape', $foreign_key["source"])) . ") REFERENCES " return " FOREIGN KEY (" . implode(", ", array_map('Adminer\idf_escape', $foreign_key["source"])) . ") REFERENCES "
. ($db != "" && $db != $_GET["db"] ? idf_escape($db) . "." : "") . ($db != "" && $db != $_GET["db"] ? idf_escape($db) . "." : "")
. ($ns != "" && $ns != $_GET["ns"] ? idf_escape($ns) . "." : "") . ($ns != "" && $ns != $_GET["ns"] ? idf_escape($ns) . "." : "")
. table($foreign_key["table"]) . idf_escape($foreign_key["table"])
. " (" . implode(", ", array_map('idf_escape', $foreign_key["target"])) . ")" //! reuse $name - check in older MySQL versions . " (" . implode(", ", array_map('Adminer\idf_escape', $foreign_key["target"])) . ")" //! reuse $name - check in older MySQL versions
. (preg_match("~^($on_actions)\$~", $foreign_key["on_delete"]) ? " ON DELETE $foreign_key[on_delete]" : "") . (preg_match("~^($driver->onActions)\$~", $foreign_key["on_delete"]) ? " ON DELETE $foreign_key[on_delete]" : "")
. (preg_match("~^($on_actions)\$~", $foreign_key["on_update"]) ? " ON UPDATE $foreign_key[on_update]" : "") . (preg_match("~^($driver->onActions)\$~", $foreign_key["on_update"]) ? " ON UPDATE $foreign_key[on_update]" : "")
; ;
} }
@@ -596,34 +598,37 @@ function tar_file($filename, $tmp_file) {
function ini_bytes($ini) { function ini_bytes($ini) {
$val = ini_get($ini); $val = ini_get($ini);
switch (strtolower(substr($val, -1))) { switch (strtolower(substr($val, -1))) {
case 'g': $val = (int)$val * 1024; // no break case 'g':
case 'm': $val = (int)$val * 1024; // no break $val = (int) $val * 1024; // no break
case 'k': $val = (int)$val * 1024; case 'm':
$val = (int) $val * 1024; // no break
case 'k':
$val = (int) $val * 1024;
} }
return $val; return $val;
} }
/** Create link to database documentation /** Create link to database documentation
* @param array $jush => $path * @param array JUSH => $path
* @param string HTML code * @param string HTML code
* @return string HTML code * @return string HTML code
*/ */
function doc_link($paths, $text = "<sup>?</sup>") { function doc_link($paths, $text = "<sup>?</sup>") {
global $jush, $connection; global $connection;
$server_info = $connection->server_info; $server_info = $connection->server_info;
$version = preg_replace('~^(\d\.?\d).*~s', '\1', $server_info); // two most significant digits $version = preg_replace('~^(\d\.?\d).*~s', '\1', $server_info); // two most significant digits
$urls = array( $urls = array(
'sql' => "https://dev.mysql.com/doc/refman/$version/en/", 'sql' => "https://dev.mysql.com/doc/refman/$version/en/",
'sqlite' => "https://www.sqlite.org/", 'sqlite' => "https://www.sqlite.org/",
'pgsql' => "https://www.postgresql.org/docs/$version/", 'pgsql' => "https://www.postgresql.org/docs/$version/",
'mssql' => "https://msdn.microsoft.com/library/", '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=", '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 (preg_match('~MariaDB~', $server_info)) {
$urls['sql'] = "https://mariadb.com/kb/en/"; $urls['sql'] = "https://mariadb.com/kb/en/";
$paths['sql'] = (isset($paths['mariadb']) ? $paths['mariadb'] : str_replace(".html", "/", $paths['sql'])); $paths['sql'] = (isset($paths['mariadb']) ? $paths['mariadb'] : str_replace(".html", "/", $paths['sql']));
} }
return ($paths[$jush] ? "<a href='" . h($urls[$jush] . $paths[$jush]) . "'" . target_blank() . ">$text</a>" : ""); return ($paths[JUSH] ? "<a href='" . h($urls[JUSH] . $paths[JUSH] . (JUSH == 'mssql' ? "?view=sql-server-ver$version" : "")) . "'" . target_blank() . ">$text</a>" : "");
} }
/** Wrap gzencode() for usage in ob_start() /** Wrap gzencode() for usage in ob_start()

View File

@@ -1,7 +1,7 @@
<?php <?php
function adminer_errors($errno, $errstr) { namespace Adminer;
return !!preg_match('~^(Trying to access array offset on( value of type)? null|Undefined (array key|property))~', $errstr);
}
error_reporting(6135); // errors and warnings error_reporting(6135); // errors and warnings
set_error_handler('adminer_errors', E_WARNING); set_error_handler(function ($errno, $errstr) {
return !!preg_match('~^(Trying to access array offset on( value of type)? null|Undefined (array key|property))~', $errstr);
}, E_WARNING);

View File

@@ -1,8 +1,10 @@
<?php <?php
namespace Adminer;
// This file is used both in Adminer and Adminer Editor. // This file is used both in Adminer and Adminer Editor.
/** Get database connection /** Get database connection
* @return Min_DB * @return Db
*/ */
function connection() { function connection() {
// can be used in customization, $connection is minified // can be used in customization, $connection is minified
@@ -96,7 +98,7 @@ function bracket_escape($idf, $back = false) {
/** Check if connection has at least the given version /** Check if connection has at least the given version
* @param string required version * @param string required version
* @param string required MariaDB version * @param string required MariaDB version
* @param Min_DB defaults to $connection * @param Db defaults to $connection
* @return bool * @return bool
*/ */
function min_version($version, $maria_db = "", $connection2 = null) { function min_version($version, $maria_db = "", $connection2 = null) {
@@ -113,7 +115,7 @@ function min_version($version, $maria_db = "", $connection2 = null) {
} }
/** Get connection charset /** Get connection charset
* @param Min_DB * @param Db
* @return string * @return string
*/ */
function charset($connection) { function charset($connection) {
@@ -354,7 +356,7 @@ function get_vals($query, $column = 0) {
/** Get keys from first column and values from second /** Get keys from first column and values from second
* @param string * @param string
* @param Min_DB * @param Db
* @param bool * @param bool
* @return array * @return array
*/ */
@@ -379,7 +381,7 @@ function get_key_vals($query, $connection2 = null, $set_keys = true) {
/** Get all rows of result /** Get all rows of result
* @param string * @param string
* @param Min_DB * @param Db
* @param string * @param string
* @return array of associative arrays * @return array of associative arrays
*/ */
@@ -392,7 +394,7 @@ function get_rows($query, $connection2 = null, $error = "<p class='error'>") {
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
$return[] = $row; $return[] = $row;
} }
} elseif (!$result && !is_object($connection2) && $error && (defined("PAGE_HEADER") || $error == "-- ")) { } elseif (!$result && !is_object($connection2) && $error && (defined('Adminer\PAGE_HEADER') || $error == "-- ")) {
echo $error . error() . "\n"; echo $error . error() . "\n";
} }
return $return; return $return;
@@ -435,19 +437,19 @@ function escape_key($key) {
* @return string * @return string
*/ */
function where($where, $fields = array()) { function where($where, $fields = array()) {
global $connection, $jush; global $connection;
$return = array(); $return = array();
foreach ((array) $where["where"] as $key => $val) { foreach ((array) $where["where"] as $key => $val) {
$key = bracket_escape($key, 1); // 1 - back $key = bracket_escape($key, 1); // 1 - back
$column = escape_key($key); $column = escape_key($key);
$return[] = $column $return[] = $column
. ($jush == "sql" && $fields[$key]["type"] == "json" ? " = CAST(" . q($val) . " AS JSON)" . (JUSH == "sql" && $fields[$key]["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 == "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 : (JUSH == "mssql" ? " LIKE " . q(preg_replace('~[_%[]~', '[\0]', $val)) // LIKE because of text
: " = " . unconvert_field($fields[$key], q($val)) : " = " . unconvert_field($fields[$key], q($val))
))) )))
; //! enum and set ; //! 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~', $fields[$key]["type"]) && preg_match("~[^ -@]~", $val)) { // not just [a-z] to catch non-ASCII characters
$return[] = "$column = " . q($val) . " COLLATE " . charset($connection) . "_bin"; $return[] = "$column = " . q($val) . " COLLATE " . charset($connection) . "_bin";
} }
} }
@@ -502,17 +504,19 @@ function convert_fields($columns, $fields, $select = array()) {
/** Set cookie valid on current path /** Set cookie valid on current path
* @param string * @param string
* @param string * @param string
* @param int number of seconds, 0 for session cookie * @param int number of seconds, 0 for session cookie, 2592000 - 30 days
* @return bool * @return bool
*/ */
function cookie($name, $value, $lifetime = 2592000) { // 2592000 - 30 days function cookie($name, $value, $lifetime = 2592000) {
global $HTTPS; global $HTTPS;
return header("Set-Cookie: $name=" . urlencode($value) return header(
. ($lifetime ? "; expires=" . gmdate("D, d M Y H:i:s", time() + $lifetime) . " GMT" : "") "Set-Cookie: $name=" . urlencode($value)
. "; path=" . preg_replace('~\?.*~', '', $_SERVER["REQUEST_URI"]) . ($lifetime ? "; expires=" . gmdate("D, d M Y H:i:s", time() + $lifetime) . " GMT" : "")
. ($HTTPS ? "; secure" : "") . "; path=" . preg_replace('~\?.*~', '', $_SERVER["REQUEST_URI"])
. "; HttpOnly; SameSite=lax", . ($HTTPS ? "; secure" : "")
false); . "; HttpOnly; SameSite=lax",
false
);
} }
/** Restart stopped session /** Restart stopped session
@@ -633,7 +637,7 @@ function query_redirect($query, $location, $message, $redirect = true, $execute
/** Execute and remember query /** Execute and remember query
* @param string or null to return remembered queries, end with ';' to use DELIMITER * @param string or null to return remembered queries, end with ';' to use DELIMITER
* @return Min_Result or array($queries, $time) if $query = null * @return Result or [$queries, $time] if $query = null
*/ */
function queries($query) { function queries($query) {
global $connection; global $connection;
@@ -731,7 +735,8 @@ function get_file($key, $decompress = false) {
} }
$name = $file["name"][$key]; $name = $file["name"][$key];
$tmp_name = $file["tmp_name"][$key]; $tmp_name = $file["tmp_name"][$key];
$content = file_get_contents($decompress && preg_match('~\.gz$~', $name) $content = file_get_contents(
$decompress && preg_match('~\.gz$~', $name)
? "compress.zlib://$tmp_name" ? "compress.zlib://$tmp_name"
: $tmp_name : $tmp_name
); //! may not be reachable because of open_basedir ); //! may not be reachable because of open_basedir
@@ -806,7 +811,7 @@ function format_number($val) {
*/ */
function friendly_url($val) { function friendly_url($val) {
// used for blobs and export // used for blobs and export
return preg_replace('~[^a-z0-9_]~i', '-', $val); return preg_replace('~\W~i', '-', $val);
} }
/** Print hidden fields /** Print hidden fields
@@ -846,12 +851,12 @@ function hidden_fields_get() {
*/ */
function table_status1($table, $fast = false) { function table_status1($table, $fast = false) {
$return = table_status($table, $fast); $return = table_status($table, $fast);
return ($return ? $return : array("Name" => $table)); return ($return ?: array("Name" => $table));
} }
/** Find out foreign keys for each column /** Find out foreign keys for each column
* @param string * @param string
* @return array [$col => array()] * @return array [$col => []]
*/ */
function column_foreign_keys($table) { function column_foreign_keys($table) {
global $adminer; global $adminer;
@@ -873,13 +878,13 @@ function column_foreign_keys($table) {
* @return null * @return null
*/ */
function enum_input($type, $attrs, $field, $value, $empty = null) { function enum_input($type, $attrs, $field, $value, $empty = null) {
global $adminer, $jush; global $adminer;
preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches); preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
$return = ($empty !== null ? "<label><input type='$type'$attrs value='$empty'" . ((is_array($value) ? in_array($empty, $value) : $value === 0) ? " checked" : "") . "><i>" . lang('empty') . "</i></label>" : ""); $return = ($empty !== null ? "<label><input type='$type'$attrs value='$empty'" . ((is_array($value) ? in_array($empty, $value) : $value === 0) ? " checked" : "") . "><i>" . lang('empty') . "</i></label>" : "");
foreach ($matches[1] as $i => $val) { foreach ($matches[1] as $i => $val) {
$val = stripcslashes(str_replace("''", "'", $val)); $val = stripcslashes(str_replace("''", "'", $val));
$checked = (is_int($value) ? $value == $i+1 : (is_array($value) ? in_array($i+1, $value) : $value === $val)); $checked = (is_int($value) ? $value == $i+1 : (is_array($value) ? in_array($i+1, $value) : $value === $val));
$return .= " <label><input type='$type'$attrs value='" . ($jush == "sql" ? $i+1 : h($val)) . "'" . ($checked ? ' checked' : '') . '>' . h($adminer->editVal($val, $field)) . '</label>'; $return .= " <label><input type='$type'$attrs value='" . (JUSH == "sql" ? $i+1 : h($val)) . "'" . ($checked ? ' checked' : '') . '>' . h($adminer->editVal($val, $field)) . '</label>';
} }
return $return; return $return;
} }
@@ -891,7 +896,7 @@ function enum_input($type, $attrs, $field, $value, $empty = null) {
* @return null * @return null
*/ */
function input($field, $value, $function) { function input($field, $value, $function) {
global $types, $structured_types, $adminer, $jush; global $driver, $adminer;
$name = h(bracket_escape($field["field"])); $name = h(bracket_escape($field["field"]));
echo "<td class='function'>"; echo "<td class='function'>";
if (is_array($value) && !$function) { if (is_array($value) && !$function) {
@@ -902,18 +907,20 @@ function input($field, $value, $function) {
$value = call_user_func_array('json_encode', $args); //! requires PHP 5.2 $value = call_user_func_array('json_encode', $args); //! requires PHP 5.2
$function = "json"; $function = "json";
} }
$reset = ($jush == "mssql" && $field["auto_increment"]); $reset = (JUSH == "mssql" && $field["auto_increment"]);
if ($reset && !$_POST["save"]) { if ($reset && !$_POST["save"]) {
$function = null; $function = null;
} }
$functions = (isset($_GET["select"]) || $reset ? array("orig" => lang('original')) : array()) + $adminer->editFunctions($field); $functions = (isset($_GET["select"]) || $reset ? array("orig" => lang('original')) : array()) + $adminer->editFunctions($field);
$disabled = stripos($field["default"], "GENERATED ALWAYS AS ") === 0 ? " disabled=''" : ""; $disabled = stripos($field["default"], "GENERATED ALWAYS AS ") === 0 ? " disabled=''" : "";
$attrs = " name='fields[$name]'$disabled"; $attrs = " name='fields[$name]'$disabled";
if ($jush == "pgsql" && in_array($field["type"], (array) $structured_types[lang('User types')])) { $types = $driver->types();
$enums = get_vals("SELECT enumlabel FROM pg_enum WHERE enumtypid = " . $types[$field["type"]] . " ORDER BY enumsortorder"); $structured_types = $driver->structuredTypes();
if (in_array($field["type"], (array) $structured_types[lang('User types')])) {
$enums = type_values($types[$field["type"]]);
if ($enums) { if ($enums) {
$field["type"] = "enum"; $field["type"] = "enum";
$field["length"] = "'" . implode("','", array_map('addslashes', $enums)) . "'"; $field["length"] = $enums;
} }
} }
if ($field["type"] == "enum") { if ($field["type"] == "enum") {
@@ -942,7 +949,7 @@ function input($field, $value, $function) {
} elseif (preg_match('~blob|bytea|raw|file~', $field["type"]) && ini_bool("file_uploads")) { } elseif (preg_match('~blob|bytea|raw|file~', $field["type"]) && ini_bool("file_uploads")) {
echo "<input type='file' name='fields-$name'>"; echo "<input type='file' name='fields-$name'>";
} elseif (($text = preg_match('~text|lob|memo~i', $field["type"])) || preg_match("~\n~", $value)) { } elseif (($text = preg_match('~text|lob|memo~i', $field["type"])) || preg_match("~\n~", $value)) {
if ($text && $jush != "sqlite") { if ($text && JUSH != "sqlite") {
$attrs .= " cols='50' rows='12'"; $attrs .= " cols='50' rows='12'";
} else { } else {
$rows = min(12, substr_count($value, "\n") + 1); $rows = min(12, substr_count($value, "\n") + 1);
@@ -957,7 +964,7 @@ function input($field, $value, $function) {
? ((preg_match("~binary~", $field["type"]) ? 2 : 1) * $match[1] + ($match[3] ? 1 : 0) + ($match[2] && !$field["unsigned"] ? 1 : 0)) ? ((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) : ($types[$field["type"]] ? $types[$field["type"]] + ($field["unsigned"] ? 0 : 1) : 0)
); );
if ($jush == 'sql' && min_version(5.6) && preg_match('~time~', $field["type"])) { if (JUSH == 'sql' && min_version(5.6) && preg_match('~time~', $field["type"])) {
$maxlength += 7; // microtime $maxlength += 7; // microtime
} }
// type='date' and type='time' display localized value which may be confusing, type='datetime' uses 'T' as date and time separator // type='date' and type='time' display localized value which may be confusing, type='datetime' uses 'T' as date and time separator
@@ -1279,9 +1286,8 @@ function is_shortable($field) {
* @return string * @return string
*/ */
function count_rows($table, $where, $is_group, $group) { function count_rows($table, $where, $is_group, $group) {
global $jush;
$query = " FROM " . table($table) . ($where ? " WHERE " . implode(" AND ", $where) : ""); $query = " FROM " . table($table) . ($where ? " WHERE " . implode(" AND ", $where) : "");
return ($is_group && ($jush == "sql" || count($group) == 1) return ($is_group && (JUSH == "sql" || count($group) == 1)
? "SELECT COUNT(DISTINCT " . implode(", ", $group) . ")$query" ? "SELECT COUNT(DISTINCT " . implode(", ", $group) . ")$query"
: "SELECT COUNT(*)" . ($is_group ? " FROM (SELECT 1$query GROUP BY " . implode(", ", $group) . ") x" : $query) : "SELECT COUNT(*)" . ($is_group ? " FROM (SELECT 1$query GROUP BY " . implode(", ", $group) . ") x" : $query)
); );
@@ -1311,7 +1317,7 @@ var timeout = setTimeout(function () {
} }
ob_flush(); ob_flush();
flush(); flush();
$return = @get_key_vals(($slow_query ? $slow_query : $query), $connection2, false); // @ - may be killed $return = @get_key_vals(($slow_query ?: $query), $connection2, false); // @ - may be killed
if ($connection2) { if ($connection2) {
echo script("clearTimeout(timeout);"); echo script("clearTimeout(timeout);");
ob_flush(); ob_flush();
@@ -1391,7 +1397,7 @@ function on_help($command, $side = 0) {
* @return null * @return null
*/ */
function edit_form($table, $fields, $row, $update) { function edit_form($table, $fields, $row, $update) {
global $adminer, $jush, $token, $error; global $adminer, $token, $error;
$table_name = $adminer->tableName(table_status1($table, true)); $table_name = $adminer->tableName(table_status1($table, true));
page_header( page_header(
($update ? lang('Edit') : lang('Insert')), ($update ? lang('Edit') : lang('Insert')),
@@ -1411,6 +1417,7 @@ function edit_form($table, $fields, $row, $update) {
echo "<p class='error'>" . lang('You have no privileges to update this table.') . "\n"; echo "<p class='error'>" . lang('You have no privileges to update this table.') . "\n";
} else { } else {
echo "<table class='layout'>" . script("qsl('table').onkeydown = editingKeydown;"); echo "<table class='layout'>" . script("qsl('table').onkeydown = editingKeydown;");
$first = 0;
foreach ($fields as $name => $field) { foreach ($fields as $name => $field) {
echo "<tr><th>" . $adminer->fieldName($field); echo "<tr><th>" . $adminer->fieldName($field);
$default = $_GET["set"][bracket_escape($name)]; $default = $_GET["set"][bracket_escape($name)];
@@ -1421,7 +1428,7 @@ function edit_form($table, $fields, $row, $update) {
} }
} }
$value = ($row !== null $value = ($row !== null
? ($row[$name] != "" && $jush == "sql" && preg_match("~enum|set~", $field["type"]) ? ($row[$name] != "" && JUSH == "sql" && preg_match("~enum|set~", $field["type"])
? (is_array($row[$name]) ? array_sum($row[$name]) : +$row[$name]) ? (is_array($row[$name]) ? array_sum($row[$name]) : +$row[$name])
: (is_bool($row[$name]) ? +$row[$name] : $row[$name]) : (is_bool($row[$name]) ? +$row[$name] : $row[$name])
) )
@@ -1451,6 +1458,9 @@ function edit_form($table, $fields, $row, $update) {
$value = ""; $value = "";
$function = "uuid"; $function = "uuid";
} }
if ($field["auto_increment"] || $function == "now" || $function == "uuid") {
$first++;
}
input($field, $value, $function); input($field, $value, $function);
echo "\n"; echo "\n";
} }
@@ -1477,7 +1487,7 @@ function edit_form($table, $fields, $row, $update) {
} }
} }
echo ($update ? "<input type='submit' name='delete' value='" . lang('Delete') . "'>" . confirm() . "\n" echo ($update ? "<input type='submit' name='delete' value='" . lang('Delete') . "'>" . confirm() . "\n"
: ($_POST || !$fields ? "" : script("focus(qsa('td', qs('#form'))[1].firstChild);")) : ($_POST || !$fields ? "" : script("focus(qsa('td', qs('#form'))[2*$first+1].firstChild);"))
); );
if (isset($_GET["select"])) { if (isset($_GET["select"])) {
hidden_fields(array("check" => (array) $_POST["check"], "clone" => $_POST["clone"], "all" => $_POST["all"])); hidden_fields(array("check" => (array) $_POST["check"], "clone" => $_POST["clone"], "all" => $_POST["all"]));

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
// not used in a single language version // not used in a single language version
$langs = array( $langs = array(
@@ -63,7 +65,7 @@ function get_lang() {
*/ */
function lang($idf, $number = null) { function lang($idf, $number = null) {
global $LANG, $translations; global $LANG, $translations;
$translation = ($translations[$idf] ? $translations[$idf] : $idf); $translation = ($translations[$idf] ?: $idf);
if (is_array($translation)) { if (is_array($translation)) {
$pos = ($number == 1 ? 0 $pos = ($number == 1 ? 0
: ($LANG == 'cs' || $LANG == 'sk' ? ($number && $number < 5 ? 1 : 2) // different forms for 1, 2-4, other : ($LANG == 'cs' || $LANG == 'sk' ? ($number && $number < 5 ? 1 : 2) // different forms for 1, 2-4, other

View File

@@ -1,29 +1,23 @@
<?php <?php
namespace Adminer;
// PDO can be used in several database drivers // PDO can be used in several database drivers
if (extension_loaded('pdo')) { if (extension_loaded('pdo')) {
/*abstract*/ class Min_PDO { abstract class PdoDb {
var $_result, $server_info, $affected_rows, $errno, $error, $pdo; var $_result, $server_info, $affected_rows, $errno, $error, $pdo;
function __construct() {
global $adminer;
$pos = array_search("SQL", $adminer->operators);
if ($pos !== false) {
unset($adminer->operators[$pos]);
}
}
function dsn($dsn, $username, $password, $options = array()) { function dsn($dsn, $username, $password, $options = array()) {
$options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_SILENT; $options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_SILENT;
$options[PDO::ATTR_STATEMENT_CLASS] = array('Min_PDOStatement'); $options[\PDO::ATTR_STATEMENT_CLASS] = array('Adminer\PdoDbStatement');
try { try {
$this->pdo = new PDO($dsn, $username, $password, $options); $this->pdo = new \PDO($dsn, $username, $password, $options);
} catch (Exception $ex) { } catch (Exception $ex) {
auth_error(h($ex->getMessage())); auth_error(h($ex->getMessage()));
} }
$this->server_info = @$this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION); $this->server_info = @$this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION);
} }
/*abstract function select_db($database);*/ abstract function select_db($database);
function quote($string) { function quote($string) {
return $this->pdo->quote($string); return $this->pdo->quote($string);
@@ -80,15 +74,15 @@ if (extension_loaded('pdo')) {
} }
} }
class Min_PDOStatement extends PDOStatement { class PdoDbStatement extends \PDOStatement {
var $_offset = 0, $num_rows; var $_offset = 0, $num_rows;
function fetch_assoc() { function fetch_assoc() {
return $this->fetch(PDO::FETCH_ASSOC); return $this->fetch(\PDO::FETCH_ASSOC);
} }
function fetch_row() { function fetch_row() {
return $this->fetch(PDO::FETCH_NUM); return $this->fetch(\PDO::FETCH_NUM);
} }
function fetch_field() { function fetch_field() {
@@ -98,5 +92,11 @@ if (extension_loaded('pdo')) {
$row->charsetnr = (in_array("blob", (array) $row->flags) ? 63 : 0); $row->charsetnr = (in_array("blob", (array) $row->flags) ? 63 : 0);
return $row; return $row;
} }
function seek($offset) {
for ($i=0; $i < $offset; $i++) {
$this->fetch();
}
}
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
namespace Adminer;
class TmpFile { class TmpFile {
var $handler; var $handler;
@@ -18,5 +19,4 @@ class TmpFile {
fpassthru($this->handler); fpassthru($this->handler);
fclose($this->handler); fclose($this->handler);
} }
} }

View File

@@ -1,2 +1,4 @@
<?php <?php
$VERSION = "4.17.0"; namespace Adminer;
$VERSION = "5.0.0";

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
/** PHP implementation of XXTEA encryption algorithm /** PHP implementation of XXTEA encryption algorithm
* @author Ma Bingyao <andot@ujn.edu.cn> * @author Ma Bingyao <andot@ujn.edu.cn>
* @link http://www.coolcode.cn/?action=show&id=128 * @link http://www.coolcode.cn/?action=show&id=128

View File

@@ -7,12 +7,11 @@
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other) * @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/ */
namespace Adminer;
include "./include/bootstrap.inc.php"; include "./include/bootstrap.inc.php";
include "./include/tmpfile.inc.php"; include "./include/tmpfile.inc.php";
$enum_length = "'(?:''|[^'\\\\]|\\\\.)*'";
$inout = "IN|OUT|INOUT";
if (isset($_GET["select"]) && ($_POST["edit"] || $_POST["clone"]) && !$_POST["save"]) { if (isset($_GET["select"]) && ($_POST["edit"] || $_POST["clone"]) && !$_POST["save"]) {
$_GET["edit"] = $_GET["select"]; $_GET["edit"] = $_GET["select"];
} }

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$TABLE = $_GET["indexes"]; $TABLE = $_GET["indexes"];
$index_types = array("PRIMARY", "UNIQUE", "INDEX"); $index_types = array("PRIMARY", "UNIQUE", "INDEX");
$table_status = table_status($TABLE, true); $table_status = table_status($TABLE, true);
@@ -10,7 +12,7 @@ if (preg_match('~MyISAM|M?aria' . (min_version(5.7, '10.2.2') ? '|InnoDB' : '')
} }
$indexes = indexes($TABLE); $indexes = indexes($TABLE);
$primary = array(); $primary = array();
if ($jush == "mongo") { // doesn't support primary key if (JUSH == "mongo") { // doesn't support primary key
$primary = $indexes["_id_"]; $primary = $indexes["_id_"];
unset($index_types[0]); unset($index_types[0]);
unset($indexes["_id_"]); unset($indexes["_id_"]);
@@ -35,27 +37,28 @@ if ($_POST && !$error && !$_POST["add"] && !$_POST["drop_col"]) {
$desc = $index["descs"][$key]; $desc = $index["descs"][$key];
$set[] = idf_escape($column) . ($length ? "(" . (+$length) . ")" : "") . ($desc ? " DESC" : ""); $set[] = idf_escape($column) . ($length ? "(" . (+$length) . ")" : "") . ($desc ? " DESC" : "");
$columns[] = $column; $columns[] = $column;
$lengths[] = ($length ? $length : null); $lengths[] = ($length ?: null);
$descs[] = $desc; $descs[] = $desc;
} }
} }
if ($columns) { $existing = $indexes[$name];
$existing = $indexes[$name]; if ($existing) {
if ($existing) { ksort($existing["columns"]);
ksort($existing["columns"]); ksort($existing["lengths"]);
ksort($existing["lengths"]); ksort($existing["descs"]);
ksort($existing["descs"]); if (
if ($index["type"] == $existing["type"] $index["type"] == $existing["type"]
&& array_values($existing["columns"]) === $columns && array_values($existing["columns"]) === $columns
&& (!$existing["lengths"] || array_values($existing["lengths"]) === $lengths) && (!$existing["lengths"] || array_values($existing["lengths"]) === $lengths)
&& array_values($existing["descs"]) === $descs && array_values($existing["descs"]) === $descs
) { ) {
// skip existing index // skip existing index
unset($indexes[$name]); unset($indexes[$name]);
continue; continue;
}
} }
}
if ($columns) {
$alter[] = array($index["type"], $name, $set); $alter[] = array($index["type"], $name, $set);
} }
} }
@@ -93,7 +96,7 @@ if (!$row) {
$indexes[] = array("columns" => array(1 => "")); $indexes[] = array("columns" => array(1 => ""));
$row["indexes"] = $indexes; $row["indexes"] = $indexes;
} }
$lengths = ($jush == "sql" || $jush == "mssql"); $lengths = (JUSH == "sql" || JUSH == "mssql");
$show_options = ($_POST ? $_POST["options"] : adminer_setting("index_options")); $show_options = ($_POST ? $_POST["options"] : adminer_setting("index_options"));
?> ?>
@@ -133,7 +136,7 @@ foreach ($row["indexes"] as $index) {
" name='indexes[$j][columns][$i]' title='" . lang('Column') . "'", " name='indexes[$j][columns][$i]' title='" . lang('Column') . "'",
($fields ? array_combine($fields, $fields) : $fields), ($fields ? array_combine($fields, $fields) : $fields),
$column, $column,
"partial(" . ($i == count($index["columns"]) ? "indexesAddColumn" : "indexesChangeColumn") . ", '" . js_escape($jush == "sql" ? "" : $_GET["indexes"] . "_") . "')" "partial(" . ($i == count($index["columns"]) ? "indexesAddColumn" : "indexesChangeColumn") . ", '" . js_escape(JUSH == "sql" ? "" : $_GET["indexes"] . "_") . "')"
); );
echo "<span class='idxopts" . ($show_options ? "" : " hidden") . "'>"; echo "<span class='idxopts" . ($show_options ? "" : " hidden") . "'>";
echo ($lengths ? "<input type='number' name='indexes[$j][lengths][$i]' class='size' value='" . h($index["lengths"][$key]) . "' title='" . lang('Length') . "'>" : ""); echo ($lengths ? "<input type='number' name='indexes[$j][lengths][$i]' class='size' value='" . h($index["lengths"][$key]) . "' title='" . lang('Length') . "'>" : "");

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'تسجيل الدخول', 'Login' => 'تسجيل الدخول',
'Logout successful.' => 'تم تسجيل الخروج بنجاح.', 'Logout successful.' => 'تم تسجيل الخروج بنجاح.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Система', 'System' => 'Система',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'লগইন', 'Login' => 'লগইন',
'Logout successful.' => 'সফলভাবে লগআউট হয়েছে।', 'Logout successful.' => 'সফলভাবে লগআউট হয়েছে।',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Sistem', 'System' => 'Sistem',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Inicia la sessió', 'Login' => 'Inicia la sessió',
'Logout successful.' => 'Desconnexió correcta.', 'Logout successful.' => 'Desconnexió correcta.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Systém', 'System' => 'Systém',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'System' => 'System', 'System' => 'System',
'Server' => 'Server', 'Server' => 'Server',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Login', 'Login' => 'Login',
'Logout successful.' => 'Abmeldung erfolgreich.', 'Logout successful.' => 'Abmeldung erfolgreich.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Σύστημα', 'System' => 'Σύστημα',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Too many unsuccessful logins, try again in %d minute(s).' => array('Too many unsuccessful logins, try again in %d minute.', 'Too many unsuccessful logins, try again in %d minutes.'), 'Too many unsuccessful logins, try again in %d minute(s).' => array('Too many unsuccessful logins, try again in %d minute.', 'Too many unsuccessful logins, try again in %d minutes.'),
'Query executed OK, %d row(s) affected.' => array('Query executed OK, %d row affected.', 'Query executed OK, %d rows affected.'), 'Query executed OK, %d row(s) affected.' => array('Query executed OK, %d row affected.', 'Query executed OK, %d rows affected.'),

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Login', 'Login' => 'Login',
'Logout successful.' => 'Sesión finalizada con éxito.', 'Logout successful.' => 'Sesión finalizada con éxito.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Logi sisse', 'Login' => 'Logi sisse',
'Logout successful.' => 'Väljalogimine õnnestus.', 'Logout successful.' => 'Väljalogimine õnnestus.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'سیستم', 'System' => 'سیستم',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Järjestelmä', 'System' => 'Järjestelmä',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Authentification', 'Login' => 'Authentification',
'Logout successful.' => 'Au revoir !', 'Logout successful.' => 'Au revoir !',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Conectar', 'Login' => 'Conectar',
'Logout successful.' => 'Pechouse a sesión con éxito.', 'Logout successful.' => 'Pechouse a sesión con éxito.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'התחברות', 'Login' => 'התחברות',
'Logout successful.' => 'ההתחברות הצליחה', 'Logout successful.' => 'ההתחברות הצליחה',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Belépés', 'Login' => 'Belépés',
'Logout successful.' => 'Sikeres kilépés.', 'Logout successful.' => 'Sikeres kilépés.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Sistem', 'System' => 'Sistem',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Autenticazione', 'Login' => 'Autenticazione',
'Logout successful.' => 'Uscita effettuata con successo.', 'Logout successful.' => 'Uscita effettuata con successo.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'ログイン', 'Login' => 'ログイン',
'Logout successful.' => 'ログアウト', 'Logout successful.' => 'ログアウト',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'შესვლა', 'Login' => 'შესვლა',
'Logout successful.' => 'გამოხვედით სისტემიდან.', 'Logout successful.' => 'გამოხვედით სისტემიდან.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'$1-$3-$5' => '$1-$3-$5', '$1-$3-$5' => '$1-$3-$5',
'%.3f s' => '%.3f 초', '%.3f s' => '%.3f 초',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Sistema', 'System' => 'Sistema',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Ieiet', 'Login' => 'Ieiet',
'Logout successful.' => 'Jūs veiksmīgi izgājāt no sistēmas.', 'Logout successful.' => 'Jūs veiksmīgi izgājāt no sistēmas.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Sistem', 'System' => 'Sistem',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Aanmelden', 'Login' => 'Aanmelden',
'Logout successful.' => 'Successvol afgemeld.', 'Logout successful.' => 'Successvol afgemeld.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'System' => 'System', 'System' => 'System',
'Server' => 'Server', 'Server' => 'Server',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Rodzaj bazy', 'System' => 'Rodzaj bazy',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Entrar', 'Login' => 'Entrar',
'Logout successful.' => 'Saída bem sucedida.', 'Logout successful.' => 'Saída bem sucedida.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Entrar', 'Login' => 'Entrar',
'Logout successful.' => 'Sessão terminada com sucesso.', 'Logout successful.' => 'Sessão terminada com sucesso.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Intră', 'Login' => 'Intră',
'Logout successful.' => 'Ați ieșit cu succes.', 'Logout successful.' => 'Ați ieșit cu succes.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Войти', 'Login' => 'Войти',
'Logout successful.' => 'Вы успешно покинули систему.', 'Logout successful.' => 'Вы успешно покинули систему.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'Prihlásiť sa', 'Login' => 'Prihlásiť sa',
'Logout successful.' => 'Odhlásenie prebehlo v poriadku.', 'Logout successful.' => 'Odhlásenie prebehlo v poriadku.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Sistem', 'System' => 'Sistem',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Систем', 'System' => 'Систем',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'System', 'System' => 'System',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'நுழை', 'Login' => 'நுழை',
'Logout successful.' => 'வெற்றிக‌ர‌மாய் வெளியேறியாயிற்று.', 'Logout successful.' => 'வெற்றிக‌ர‌மாய் வெளியேறியாயிற்று.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
'Login' => 'เข้าสู่ระบบ', 'Login' => 'เข้าสู่ระบบ',
'Logout successful.' => 'ออกจากระบบเรียบร้อยแล้ว.', 'Logout successful.' => 'ออกจากระบบเรียบร้อยแล้ว.',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Sistem', 'System' => 'Sistem',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Система Бази Даних', 'System' => 'Система Бази Даних',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Hệ thống', 'System' => 'Hệ thống',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => 'Xx', 'System' => 'Xx',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => '資料庫系統', 'System' => '資料庫系統',

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$translations = array( $translations = array(
// label for database system selection (MySQL, SQLite, ...) // label for database system selection (MySQL, SQLite, ...)
'System' => '系统', 'System' => '系统',

View File

@@ -20,9 +20,7 @@ function adminer_object() {
new AdminerDumpXml, new AdminerDumpXml,
new AdminerDumpAlter, new AdminerDumpAlter,
//~ new AdminerSqlLog("past-" . rtrim(`git describe --tags --abbrev=0`) . ".sql"), //~ new AdminerSqlLog("past-" . rtrim(`git describe --tags --abbrev=0`) . ".sql"),
//~ new AdminerEditCalendar(script_src("../externals/jquery-ui/jquery-1.4.4.js") . script_src("../externals/jquery-ui/ui/jquery.ui.core.js") . script_src("../externals/jquery-ui/ui/jquery.ui.widget.js") . script_src("../externals/jquery-ui/ui/jquery.ui.datepicker.js") . script_src("../externals/jquery-ui/ui/jquery.ui.mouse.js") . script_src("../externals/jquery-ui/ui/jquery.ui.slider.js") . script_src("../externals/jquery-timepicker/jquery-ui-timepicker-addon.js") . "<link rel='stylesheet' href='../externals/jquery-ui/themes/base/jquery.ui.all.css'>\n<style>\n.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }\n.ui-timepicker-div dl { text-align: left; }\n.ui-timepicker-div dl dt { height: 25px; }\n.ui-timepicker-div dl dd { margin: -25px 0 10px 65px; }\n.ui-timepicker-div td { font-size: 90%; }\n</style>\n", "../externals/jquery-ui/ui/i18n/jquery.ui.datepicker-%s.js"),
//~ new AdminerTinymce("../externals/tinymce/jscripts/tiny_mce/tiny_mce_dev.js"), //~ new AdminerTinymce("../externals/tinymce/jscripts/tiny_mce/tiny_mce_dev.js"),
//~ new AdminerWymeditor(array("../externals/wymeditor/src/jquery/jquery.js", "../externals/wymeditor/src/wymeditor/jquery.wymeditor.js", "../externals/wymeditor/src/wymeditor/jquery.wymeditor.explorer.js", "../externals/wymeditor/src/wymeditor/jquery.wymeditor.mozilla.js", "../externals/wymeditor/src/wymeditor/jquery.wymeditor.opera.js", "../externals/wymeditor/src/wymeditor/jquery.wymeditor.safari.js")),
new AdminerFileUpload(""), new AdminerFileUpload(""),
new AdminerJsonColumn, new AdminerJsonColumn,
new AdminerSlugify, new AdminerSlugify,

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
page_header(lang('Privileges')); page_header(lang('Privileges'));
echo '<p class="links"><a href="' . h(ME) . 'user=">' . lang('Create user') . "</a>"; echo '<p class="links"><a href="' . h(ME) . 'user=">' . lang('Create user') . "</a>";

View File

@@ -1,5 +1,7 @@
<?php <?php
$PROCEDURE = ($_GET["name"] ? $_GET["name"] : $_GET["procedure"]); namespace Adminer;
$PROCEDURE = ($_GET["name"] ?: $_GET["procedure"]);
$routine = (isset($_GET["function"]) ? "FUNCTION" : "PROCEDURE"); $routine = (isset($_GET["function"]) ? "FUNCTION" : "PROCEDURE");
$row = $_POST; $row = $_POST;
$row["fields"] = (array) $row["fields"]; $row["fields"] = (array) $row["fields"];
@@ -44,7 +46,7 @@ $routine_languages = routine_languages();
edit_fields($row["fields"], $collations, $routine); edit_fields($row["fields"], $collations, $routine);
if (isset($_GET["function"])) { if (isset($_GET["function"])) {
echo "<tr><td>" . lang('Return type'); echo "<tr><td>" . lang('Return type');
edit_type("returns", $row["returns"], $collations, array(), ($jush == "pgsql" ? array("void", "trigger") : array())); edit_type("returns", $row["returns"], $collations, array(), (JUSH == "pgsql" ? array("void", "trigger") : array()));
} }
?> ?>
</table> </table>
@@ -53,6 +55,8 @@ if (isset($_GET["function"])) {
<p><?php textarea("definition", $row["definition"]); ?> <p><?php textarea("definition", $row["definition"]); ?>
<p> <p>
<input type="submit" value="<?php echo lang('Save'); ?>"> <input type="submit" value="<?php echo lang('Save'); ?>">
<?php if ($PROCEDURE != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $PROCEDURE)); ?><?php } ?> <?php if ($PROCEDURE != "") { ?>
<input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $PROCEDURE)); ?>
<?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>"> <input type="hidden" name="token" value="<?php echo $token; ?>">
</form> </form>

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
if (support("kill")) { if (support("kill")) {
if ($_POST && !$error) { if ($_POST && !$error) {
$killed = 0; $killed = 0;
@@ -22,7 +24,6 @@ echo script("mixin(qsl('table'), {onclick: tableClick, ondblclick: partialArg(ta
// HTML valid because there is always at least one process // HTML valid because there is always at least one process
$i = -1; $i = -1;
foreach (process_list() as $i => $row) { foreach (process_list() as $i => $row) {
if (!$i) { if (!$i) {
echo "<thead><tr lang='en'>" . (support("kill") ? "<th>" : ""); echo "<thead><tr lang='en'>" . (support("kill") ? "<th>" : "");
foreach ($row as $key => $val) { foreach ($row as $key => $val) {
@@ -34,13 +35,13 @@ foreach (process_list() as $i => $row) {
} }
echo "</thead>\n"; echo "</thead>\n";
} }
echo "<tr>" . (support("kill") ? "<td>" . checkbox("kill[]", $row[$jush == "sql" ? "Id" : "pid"], 0) : ""); echo "<tr>" . (support("kill") ? "<td>" . checkbox("kill[]", $row[JUSH == "sql" ? "Id" : "pid"], 0) : "");
foreach ($row as $key => $val) { foreach ($row as $key => $val) {
echo "<td>" . ( echo "<td>" . (
($jush == "sql" && $key == "Info" && preg_match("~Query|Killed~", $row["Command"]) && $val != "") || (JUSH == "sql" && $key == "Info" && preg_match("~Query|Killed~", $row["Command"]) && $val != "") ||
($jush == "pgsql" && $key == "current_query" && $val != "<IDLE>") || (JUSH == "pgsql" && $key == "current_query" && $val != "<IDLE>") ||
($jush == "oracle" && $key == "sql_text" && $val != "") (JUSH == "oracle" && $key == "sql_text" && $val != "")
? "<code class='jush-$jush'>" . shorten_utf8($val, 100, "</code>") . ' <a href="' . h(ME . ($row["db"] != "" ? "db=" . urlencode($row["db"]) . "&" : "") . "sql=" . urlencode($val)) . '">' . lang('Clone') . '</a>' ? "<code class='jush-" . JUSH . "'>" . shorten_utf8($val, 100, "</code>") . ' <a href="' . h(ME . ($row["db"] != "" ? "db=" . urlencode($row["db"]) . "&" : "") . "sql=" . urlencode($val)) . '">' . lang('Clone') . '</a>'
: h($val) : h($val)
); );
} }

View File

@@ -1,9 +1,11 @@
<?php <?php
namespace Adminer;
page_header(lang('Database schema'), "", array(), h(DB . ($_GET["ns"] ? ".$_GET[ns]" : ""))); page_header(lang('Database schema'), "", array(), h(DB . ($_GET["ns"] ? ".$_GET[ns]" : "")));
$table_pos = array(); $table_pos = array();
$table_pos_js = array(); $table_pos_js = array();
$SCHEMA = ($_GET["schema"] ? $_GET["schema"] : $_COOKIE["adminer_schema-" . str_replace(".", "_", DB)]); // $_COOKIE["adminer_schema"] was used before 3.2.0 //! ':' in table name $SCHEMA = ($_GET["schema"] ?: $_COOKIE["adminer_schema-" . str_replace(".", "_", DB)]); // $_COOKIE["adminer_schema"] was used before 3.2.0 //! ':' in table name
preg_match_all('~([^:]+):([-0-9.]+)x([-0-9.]+)(_|$)~', $SCHEMA, $matches, PREG_SET_ORDER); preg_match_all('~([^:]+):([-0-9.]+)x([-0-9.]+)(_|$)~', $SCHEMA, $matches, PREG_SET_ORDER);
foreach ($matches as $i => $match) { foreach ($matches as $i => $match) {
$table_pos[$match[1]] = array($match[2], $match[3]); $table_pos[$match[1]] = array($match[2], $match[3]);
@@ -26,7 +28,7 @@ foreach (table_status('', true) as $table => $table_status) {
$field["pos"] = $pos; $field["pos"] = $pos;
$schema[$table]["fields"][$name] = $field; $schema[$table]["fields"][$name] = $field;
} }
$schema[$table]["pos"] = ($table_pos[$table] ? $table_pos[$table] : array($top, 0)); $schema[$table]["pos"] = ($table_pos[$table] ?: array($top, 0));
foreach ($adminer->foreignKeys($table) as $val) { foreach ($adminer->foreignKeys($table) as $val) {
if (!$val["db"]) { if (!$val["db"]) {
$left = $base_left; $left = $base_left;
@@ -82,7 +84,10 @@ foreach ($schema as $name => $table) {
$left1 = $left - $table_pos[$name][1]; $left1 = $left - $table_pos[$name][1];
$i = 0; $i = 0;
foreach ($columns as $target) { 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></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>"
;
} }
} }
} }

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$row = $_POST; $row = $_POST;
if ($_POST && !$error) { if ($_POST && !$error) {

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
header("Content-Type: text/javascript; charset=utf-8"); header("Content-Type: text/javascript; charset=utf-8");
if ($_GET["script"] == "db") { if ($_GET["script"] == "db") {
@@ -12,10 +14,12 @@ if ($_GET["script"] == "db") {
foreach ($sums + array("Auto_increment" => 0, "Rows" => 0) as $key => $val) { foreach ($sums + array("Auto_increment" => 0, "Rows" => 0) as $key => $val) {
if ($table_status[$key] != "") { if ($table_status[$key] != "") {
$val = format_number($table_status[$key]); $val = format_number($table_status[$key]);
json_row("$key-$name", ($key == "Rows" && $val && $table_status["Engine"] == ($jush == "pgsql" ? "table" : "InnoDB") if ($val >= 0) {
? "~ $val" json_row("$key-$name", ($key == "Rows" && $val && $table_status["Engine"] == (JUSH == "pgsql" ? "table" : "InnoDB")
: $val ? "~ $val"
)); : $val
));
}
if (isset($sums[$key])) { if (isset($sums[$key])) {
// ignore innodb_file_per_table because it is not active for tables created before it was enabled // ignore innodb_file_per_table because it is not active for tables created before it was enabled
$sums[$key] += ($table_status["Engine"] != "InnoDB" || $key != "Data_free" ? $table_status[$key] : 0); $sums[$key] += ($table_status["Engine"] != "InnoDB" || $key != "Data_free" ? $table_status[$key] : 0);

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$TABLE = $_GET["select"]; $TABLE = $_GET["select"];
$table_status = table_status1($TABLE); $table_status = table_status1($TABLE);
$indexes = indexes($TABLE); $indexes = indexes($TABLE);
@@ -31,7 +33,7 @@ if ($_GET["val"] && is_ajax()) {
header("Content-Type: text/plain; charset=utf-8"); header("Content-Type: text/plain; charset=utf-8");
foreach ($_GET["val"] as $unique_idf => $row) { foreach ($_GET["val"] as $unique_idf => $row) {
$as = convert_field($fields[key($row)]); $as = convert_field($fields[key($row)]);
$select = array($as ? $as : idf_escape(key($row))); $select = array($as ?: idf_escape(key($row)));
$where[] = where_check($unique_idf, $fields); $where[] = where_check($unique_idf, $fields);
$return = $driver->select($TABLE, $select, $where, $select); $return = $driver->select($TABLE, $select, $where, $select);
if ($return) { if ($return) {
@@ -97,7 +99,7 @@ if ($_POST && !$error) {
$affected = 0; $affected = 0;
$set = array(); $set = array();
if (!$_POST["delete"]) { if (!$_POST["delete"]) {
foreach ($columns as $name => $val) { //! should check also for edit or insert privileges foreach ($_POST["fields"] as $name => $val) {
$val = process_input($fields[$name]); $val = process_input($fields[$name]);
if ($val !== null && ($_POST["clone"] || $val !== false)) { if ($val !== null && ($_POST["clone"] || $val !== false)) {
$set[idf_escape($name)] = ($val !== false ? $val : idf_escape($name)); $set[idf_escape($name)] = ($val !== false ? $val : idf_escape($name));
@@ -144,7 +146,8 @@ if ($_POST && !$error) {
} }
queries_redirect(remove_from_uri($_POST["all"] && $_POST["delete"] ? "page" : ""), $message, $result); queries_redirect(remove_from_uri($_POST["all"] && $_POST["delete"] ? "page" : ""), $message, $result);
if (!$_POST["delete"]) { if (!$_POST["delete"]) {
edit_form($TABLE, $fields, (array) $_POST["fields"], !$_POST["clone"]); $post_fields = (array) $_POST["fields"];
edit_form($TABLE, array_intersect_key($fields, $post_fields), $post_fields, !$_POST["clone"]);
page_footer(); page_footer();
exit; exit;
} }
@@ -198,14 +201,14 @@ if ($_POST && !$error) {
} else { } else {
$set = array(); $set = array();
foreach ($matches2[1] as $i => $col) { foreach ($matches2[1] as $i => $col) {
$set[idf_escape($cols[$i])] = ($col == "" && $fields[$cols[$i]]["null"] ? "NULL" : q(str_replace('""', '"', preg_replace('~^"|"$~', '', $col)))); $set[idf_escape($cols[$i])] = ($col == "" && $fields[$cols[$i]]["null"] ? "NULL" : q(preg_match('~^".*"$~s', $col) ? str_replace('""', '"', substr($col, 1, -1)) : $col));
} }
$rows[] = $set; $rows[] = $set;
} }
} }
$result = (!$rows || $driver->insertUpdate($TABLE, $rows, $primary)); $result = (!$rows || $driver->insertUpdate($TABLE, $rows, $primary));
if ($result) { if ($result) {
$result = $driver->commit(); $driver->commit();
} }
queries_redirect(remove_from_uri("page"), lang('%d row(s) have been imported.', $affected), $result); queries_redirect(remove_from_uri("page"), lang('%d row(s) have been imported.', $affected), $result);
$driver->rollback(); // after queries_redirect() to not overwrite error $driver->rollback(); // after queries_redirect() to not overwrite error
@@ -226,9 +229,10 @@ $set = null;
if (isset($rights["insert"]) || !support("table")) { if (isset($rights["insert"]) || !support("table")) {
$params = array(); $params = array();
foreach ((array) $_GET["where"] as $val) { foreach ((array) $_GET["where"] as $val) {
if (isset($foreign_keys[$val["col"]]) && count($foreign_keys[$val["col"]]) == 1 if (
&& ($val["op"] == "=" || (!$val["op"] && (is_array($val["val"]) || !preg_match('~[_%]~', $val["val"]))) // LIKE in Editor isset($foreign_keys[$val["col"]]) && count($foreign_keys[$val["col"]]) == 1
)) { && ($val["op"] == "=" || (!$val["op"] && (is_array($val["val"]) || !preg_match('~[_%]~', $val["val"])))) // LIKE in Editor
) {
$params["set" . "[" . bracket_escape($val["col"]) . "]"] = $val["val"]; $params["set" . "[" . bracket_escape($val["col"]) . "]"] = $val["val"];
} }
} }
@@ -288,21 +292,21 @@ if (!$columns && support("table")) {
if (!$result) { if (!$result) {
echo "<p class='error'>" . error() . "\n"; echo "<p class='error'>" . error() . "\n";
} else { } else {
if ($jush == "mssql" && $page) { if (JUSH == "mssql" && $page) {
$result->seek($limit * $page); $result->seek($limit * $page);
} }
$email_fields = array(); $email_fields = array();
echo "<form action='' method='post' enctype='multipart/form-data'>\n"; echo "<form action='' method='post' enctype='multipart/form-data'>\n";
$rows = array(); $rows = array();
while ($row = $result->fetch_assoc()) { while ($row = $result->fetch_assoc()) {
if ($page && $jush == "oracle") { if ($page && JUSH == "oracle") {
unset($row["RNUM"]); unset($row["RNUM"]);
} }
$rows[] = $row; $rows[] = $row;
} }
// use count($rows) without LIMIT, COUNT(*) without grouping, FOUND_ROWS otherwise (slowest) // use count($rows) without LIMIT, COUNT(*) without grouping, FOUND_ROWS otherwise (slowest)
if ($_GET["page"] != "last" && $limit != "" && $group && $is_group && $jush == "sql") { if ($_GET["page"] != "last" && $limit != "" && $group && $is_group && JUSH == "sql") {
$found_rows = $connection->result(" SELECT FOUND_ROWS()"); // space to allow mysql.trace_mode $found_rows = $connection->result(" SELECT FOUND_ROWS()"); // space to allow mysql.trace_mode
} }
@@ -376,9 +380,9 @@ if (!$columns && support("table")) {
} }
$unique_idf = ""; $unique_idf = "";
foreach ($unique_array as $key => $val) { foreach ($unique_array as $key => $val) {
if (($jush == "sql" || $jush == "pgsql") && preg_match('~char|text|enum|set~', $fields[$key]["type"]) && strlen($val) > 64) { if ((JUSH == "sql" || JUSH == "pgsql") && preg_match('~char|text|enum|set~', $fields[$key]["type"]) && strlen($val) > 64) {
$key = (strpos($key, '(') ? $key : idf_escape($key)); //! columns looking like functions $key = (strpos($key, '(') ? $key : idf_escape($key)); //! columns looking like functions
$key = "MD5(" . ($jush != 'sql' || preg_match("~^utf8~", $fields[$key]["collation"]) ? $key : "CONVERT($key USING " . charset($connection) . ")") . ")"; $key = "MD5(" . (JUSH != 'sql' || preg_match("~^utf8~", $fields[$key]["collation"]) ? $key : "CONVERT($key USING " . charset($connection) . ")") . ")";
$val = md5($val); $val = md5($val);
} }
$unique_idf .= "&" . ($val !== null ? urlencode("where[" . bracket_escape($key) . "]") . "=" . urlencode($val === false ? "f" : $val) : "null%5B%5D=" . urlencode($key)); $unique_idf .= "&" . ($val !== null ? urlencode("where[" . bracket_escape($key) . "]") . "=" . urlencode($val === false ? "f" : $val) : "null%5B%5D=" . urlencode($key));
@@ -433,7 +437,7 @@ if (!$columns && support("table")) {
$val = select_value($val, $link, $field, $text_length); $val = select_value($val, $link, $field, $text_length);
$id = h("val[$unique_idf][" . bracket_escape($key) . "]"); $id = h("val[$unique_idf][" . bracket_escape($key) . "]");
$value = $_POST["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]; $editable = !is_array($row[$key]) && is_utf8($val) && $rows[$n][$key] == $row[$key] && !$functions[$key] && !$field["generated"];
$text = preg_match('~text|lob~', $field["type"]); $text = preg_match('~text|lob~', $field["type"]);
echo "<td id='$id'"; echo "<td id='$id'";
if (($_GET["modify"] && $editable) || $value !== null) { if (($_GET["modify"] && $editable) || $value !== null) {
@@ -443,7 +447,7 @@ if (!$columns && support("table")) {
$long = strpos($val, "<i>…</i>"); $long = strpos($val, "<i>…</i>");
echo " data-text='" . ($long ? 2 : ($text ? 1 : 0)) . "'" echo " data-text='" . ($long ? 2 : ($text ? 1 : 0)) . "'"
. ($editable ? "" : " data-warning='" . h(lang('Use edit link to modify this value.')) . "'") . ($editable ? "" : " data-warning='" . h(lang('Use edit link to modify this value.')) . "'")
. ">$val</td>" . ">$val"
; ;
} }
} }
@@ -469,7 +473,7 @@ if (!$columns && support("table")) {
if ($_GET["page"] != "last") { if ($_GET["page"] != "last") {
if ($limit == "" || (count($rows) < $limit && ($rows || !$page))) { if ($limit == "" || (count($rows) < $limit && ($rows || !$page))) {
$found_rows = ($page ? $page * $limit : 0) + count($rows); $found_rows = ($page ? $page * $limit : 0) + count($rows);
} elseif ($jush != "sql" || !$is_group) { } elseif (JUSH != "sql" || !$is_group) {
$found_rows = ($is_group ? false : found_rows($table_status, $where)); $found_rows = ($is_group ? false : found_rows($table_status, $where));
if ($found_rows < max(1e4, 2 * ($page + 1) * $limit)) { if ($found_rows < max(1e4, 2 * ($page + 1) * $limit)) {
// slow with big tables // slow with big tables
@@ -500,7 +504,7 @@ if (!$columns && support("table")) {
: floor(($found_rows - 1) / $limit) : floor(($found_rows - 1) / $limit)
); );
echo "<fieldset>"; echo "<fieldset>";
if ($jush != "simpledb") { if (JUSH != "simpledb") {
echo "<legend><a href='" . h(remove_from_uri("page")) . "'>" . lang('Page') . "</a></legend>"; echo "<legend><a href='" . h(remove_from_uri("page")) . "'>" . lang('Page') . "</a></legend>";
echo script("qsl('a').onclick = function () { pageClick(this.href, +prompt('" . lang('Page') . "', '" . ($page + 1) . "')); return false; };"); echo script("qsl('a').onclick = function () { pageClick(this.href, +prompt('" . lang('Page') . "', '" . ($page + 1) . "')); return false; };");
echo pagination(0, $page) . ($page > 5 ? "" : ""); echo pagination(0, $page) . ($page > 5 ? "" : "");
@@ -526,9 +530,8 @@ if (!$columns && support("table")) {
echo "<fieldset>"; echo "<fieldset>";
echo "<legend>" . lang('Whole result') . "</legend>"; echo "<legend>" . lang('Whole result') . "</legend>";
$display_rows = ($exact_count ? "" : "~ ") . $found_rows; $display_rows = ($exact_count ? "" : "~ ") . $found_rows;
echo checkbox("all", 1, 0, ($found_rows !== false ? ($exact_count ? "" : "~ ") . lang('%d row(s)', $found_rows) : ""), $onclick = "var checked = formChecked(this, /check/); selectCount('selected', this.checked ? '$display_rows' : checked); selectCount('selected2', this.checked || !checked ? '$display_rows' : checked);";
"var checked = formChecked(this, /check/); selectCount('selected', this.checked ? '$display_rows' : checked); selectCount('selected2', this.checked || !checked ? '$display_rows' : checked);" echo checkbox("all", 1, 0, ($found_rows !== false ? ($exact_count ? "" : "~ ") . lang('%d row(s)', $found_rows) : ""), $onclick) . "\n";
) . "\n";
echo "</fieldset>\n"; echo "</fieldset>\n";
if ($adminer->selectCommandPrint()) { if ($adminer->selectCommandPrint()) {
@@ -569,7 +572,7 @@ if (!$columns && support("table")) {
echo "<div>"; echo "<div>";
echo "<a href='#import'>" . lang('Import') . "</a>"; echo "<a href='#import'>" . lang('Import') . "</a>";
echo script("qsl('a').onclick = partial(toggle, 'import');", ""); echo script("qsl('a').onclick = partial(toggle, 'import');", "");
echo "<span id='import' class='hidden'>: "; echo "<span id='import'" . ($_POST["import"] ? "" : " class='hidden'") . ">: ";
echo "<input type='file' name='csv_file'> "; echo "<input type='file' name='csv_file'> ";
echo html_select("separator", array("csv" => "CSV,", "csv;" => "CSV;", "tsv" => "TSV"), $adminer_import["format"], 1); // 1 - select echo html_select("separator", array("csv" => "CSV,", "csv;" => "CSV;", "tsv" => "TSV"), $adminer_import["format"], 1); // 1 - select
echo " <input type='submit' name='import' value='" . lang('Import') . "'>"; echo " <input type='submit' name='import' value='" . lang('Import') . "'>";

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$SEQUENCE = $_GET["sequence"]; $SEQUENCE = $_GET["sequence"];
$row = $_POST; $row = $_POST;

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
if (!$error && $_POST["export"]) { if (!$error && $_POST["export"]) {
dump_headers("sql"); dump_headers("sql");
$adminer->dumpTable("", ""); $adminer->dumpTable("", "");
@@ -59,7 +61,7 @@ if (!$error && $_POST) {
} }
$commands = 0; $commands = 0;
$errors = array(); $errors = array();
$parse = '[\'"' . ($jush == "sql" ? '`#' : ($jush == "sqlite" ? '`[' : ($jush == "mssql" ? '[' : ''))) . ']|/\*|-- |$' . ($jush == "pgsql" ? '|\$[^$]*\$' : ''); $parse = '[\'"' . (JUSH == "sql" ? '`#' : (JUSH == "sqlite" ? '`[' : (JUSH == "mssql" ? '[' : ''))) . ']|/\*|-- |$' . (JUSH == "pgsql" ? '|\$[^$]*\$' : '');
$total_start = microtime(true); $total_start = microtime(true);
parse_str($_COOKIE["adminer_export"], $adminer_export); parse_str($_COOKIE["adminer_export"], $adminer_export);
$dump_format = $adminer->dumpFormat(); $dump_format = $adminer->dumpFormat();
@@ -81,7 +83,7 @@ if (!$error && $_POST) {
$offset = $pos + strlen($found); $offset = $pos + strlen($found);
if ($found && rtrim($found) != $delimiter) { // find matching quote or comment end if ($found && rtrim($found) != $delimiter) { // find matching quote or comment end
$c_style_escapes = is_c_style_escapes() || ($jush == "pgsql" && ($pos > 0 && strtolower($query[$pos - 1]) == "e")); $c_style_escapes = $driver->hasCStyleEscapes() || (JUSH == "pgsql" && ($pos > 0 && strtolower($query[$pos - 1]) == "e"));
$pattern = ($found == '/*' ? '\*/' $pattern = ($found == '/*' ? '\*/'
: ($found == '[' ? ']' : ($found == '[' ? ']'
@@ -105,8 +107,8 @@ if (!$error && $_POST) {
$empty = false; $empty = false;
$q = substr($query, 0, $pos); $q = substr($query, 0, $pos);
$commands++; $commands++;
$print = "<pre id='sql-$commands'><code class='jush-$jush'>" . $adminer->sqlCommandQuery($q) . "</code></pre>\n"; $print = "<pre id='sql-$commands'><code class='jush-" . JUSH . "'>" . $adminer->sqlCommandQuery($q) . "</code></pre>\n";
if ($jush == "sqlite" && preg_match("~^$space*+ATTACH\\b~i", $q, $match)) { if (JUSH == "sqlite" && preg_match("~^$space*+ATTACH\\b~i", $q, $match)) {
// PHP doesn't support setting SQLITE_LIMIT_ATTACHED // PHP doesn't support setting SQLITE_LIMIT_ATTACHED
echo $print; echo $print;
echo "<p class='error'>" . lang('ATTACH queries are not supported.') . "\n"; echo "<p class='error'>" . lang('ATTACH queries are not supported.') . "\n";
@@ -263,7 +265,7 @@ if (!isset($_GET["import"]) && $history) {
list($q, $time, $elapsed) = $val; list($q, $time, $elapsed) = $val;
echo '<a href="' . h(ME . "sql=&history=$key") . '">' . lang('Edit') . "</a>" echo '<a href="' . h(ME . "sql=&history=$key") . '">' . lang('Edit') . "</a>"
. " <span class='time' title='" . @date('Y-m-d', $time) . "'>" . @date("H:i:s", $time) . "</span>" // @ - time zone may be not set . " <span class='time' title='" . @date('Y-m-d', $time) . "'>" . @date("H:i:s", $time) . "</span>" // @ - time zone may be not set
. " <code class='jush-$jush'>" . shorten_utf8(ltrim(str_replace("\n", " ", str_replace("\r", "", preg_replace('~^(#|-- ).*~m', '', $q)))), 80, "</code>") . " <code class='jush-" . JUSH . "'>" . shorten_utf8(ltrim(str_replace("\n", " ", str_replace("\r", "", preg_replace('~^(#|-- ).*~m', '', $q)))), 80, "</code>")
. ($elapsed ? " <span class='time'>($elapsed)</span>" : "") . ($elapsed ? " <span class='time'>($elapsed)</span>" : "")
. "<br>\n" . "<br>\n"
; ;

View File

@@ -22,10 +22,12 @@ td img { max-width: 200px; max-height: 200px; }
code { background: #eee; } code { background: #eee; }
tbody tr:hover td, tbody tr:hover th { background: #eee; } tbody tr:hover td, tbody tr:hover th { background: #eee; }
pre { margin: 1em 0 0; } pre { margin: 1em 0 0; }
td pre { margin: 0; }
pre, textarea { font: 100%/1.25 monospace; } pre, textarea { font: 100%/1.25 monospace; }
pre.jush { background: #fff; } pre.jush { background: #fff; }
input, textarea { box-sizing: border-box; } input, textarea { box-sizing: border-box; }
input, select { vertical-align: middle; } input, select { vertical-align: middle; }
input[type="radio"] { vertical-align: text-bottom; }
input.default { box-shadow: 1px 1px 1px #777; } input.default { box-shadow: 1px 1px 1px #777; }
input.required { box-shadow: 1px 1px 1px red; } input.required { box-shadow: 1px 1px 1px red; }
input.maxlength { box-shadow: 1px 1px 1px red; } input.maxlength { box-shadow: 1px 1px 1px red; }

View File

@@ -238,9 +238,13 @@ function editFields() {
els = qsa('[name$="[type]"]'); els = qsa('[name$="[type]"]');
for (var i = 0; i < els.length; i++) { for (var i = 0; i < els.length; i++) {
mixin(els[i], { mixin(els[i], {
onfocus: function () { lastType = selectValue(this); }, onfocus: function () {
lastType = selectValue(this);
},
onchange: editingTypeChange, onchange: editingTypeChange,
onmouseover: function (event) { helpMouseover.call(this, event, getTarget(event).value, 1) }, onmouseover: function (event) {
helpMouseover.call(this, event, getTarget(event).value, 1);
},
onmouseout: helpMouseout onmouseout: helpMouseout
}); });
} }
@@ -286,7 +290,8 @@ function editingClick(event) {
function editingInput(event) { function editingInput(event) {
var el = getTarget(event); var el = getTarget(event);
if (/\[default]$/.test(el.name)) { if (/\[default]$/.test(el.name)) {
el.previousSibling.checked = true; el.previousElementSibling.checked = true;
el.previousElementSibling.selectedIndex = Math.max(el.previousElementSibling.selectedIndex, 1);
} }
} }
@@ -355,8 +360,9 @@ function editingAddRow(focus) {
if (/\[(orig|field|comment|default)/.test(tags[i].name)) { if (/\[(orig|field|comment|default)/.test(tags[i].name)) {
tags2[i].value = ''; tags2[i].value = '';
} }
if (/\[(has_default)/.test(tags[i].name)) { if (/\[(generated)/.test(tags[i].name)) {
tags2[i].checked = false; tags2[i].checked = false;
tags2[i].selectedIndex = 0;
} }
} }
tags[0].oninput = editingNameChange; tags[0].oninput = editingNameChange;
@@ -418,8 +424,9 @@ function editingTypeChange() {
} }
el.oninput.apply(el); el.oninput.apply(el);
} }
if (lastType == 'timestamp' && el.name == name + '[has_default]' && /timestamp/i.test(formField(type.form, name + '[default]').value)) { if (lastType == 'timestamp' && el.name == name + '[generated]' && /timestamp/i.test(formField(type.form, name + '[default]').value)) {
el.checked = false; el.checked = false;
el.selectedIndex = 0;
} }
if (el.name == name + '[collation]') { if (el.name == name + '[collation]') {
alterClass(el, 'hidden', !/(char|text|enum|set)$/.test(text)); alterClass(el, 'hidden', !/(char|text|enum|set)$/.test(text));
@@ -692,7 +699,7 @@ var that, x, y; // em and tablePos defined in schema.inc.php
* @this HTMLElement * @this HTMLElement
*/ */
function schemaMousedown(event) { function schemaMousedown(event) {
if ((event.which ? event.which : event.button) == 1) { if ((event.which || event.button) == 1) {
that = this; that = this;
x = event.clientX - this.offsetLeft; x = event.clientX - this.offsetLeft;
y = event.clientY - this.offsetTop; y = event.clientY - this.offsetTop;
@@ -711,7 +718,7 @@ function schemaMousemove(event) {
for (var i=0; i < divs.length; i++) { for (var i=0; i < divs.length; i++) {
if (divs[i].className == 'references') { if (divs[i].className == 'references') {
var div2 = qs('[id="' + (/^refs/.test(divs[i].id) ? 'refd' : 'refs') + divs[i].id.substr(4) + '"]'); var div2 = qs('[id="' + (/^refs/.test(divs[i].id) ? 'refd' : 'refs') + divs[i].id.substr(4) + '"]');
var ref = (tablePos[divs[i].title] ? tablePos[divs[i].title] : [ div2.parentNode.offsetTop / em, 0 ]); var ref = (tablePos[divs[i].title] || [ div2.parentNode.offsetTop / em, 0 ]);
var left1 = -1; var left1 = -1;
var id = divs[i].id.replace(/^ref.(.+)-.+/, '$1'); var id = divs[i].id.replace(/^ref.(.+)-.+/, '$1');
if (divs[i].parentNode != div2.parentNode) { if (divs[i].parentNode != div2.parentNode) {

View File

@@ -884,7 +884,8 @@ function addEvent(el, action, handler) {
* @param HTMLElement * @param HTMLElement
*/ */
function focus(el) { function focus(el) {
setTimeout(function () { // this has to be an anonymous function because Firefox passes some arguments to setTimeout callback setTimeout(function () {
// this has to be an anonymous function because Firefox passes some arguments to setTimeout callback
el.focus(); el.focus();
}, 0); }, 0);
} }

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$TABLE = $_GET["table"]; $TABLE = $_GET["table"];
$fields = fields($TABLE); $fields = fields($TABLE);
if (!$fields) { if (!$fields) {
@@ -42,12 +44,14 @@ if (!is_view($table_status)) {
echo "<thead><tr><th>" . lang('Source') . "<td>" . lang('Target') . "<td>" . lang('ON DELETE') . "<td>" . lang('ON UPDATE') . "<td></thead>\n"; echo "<thead><tr><th>" . lang('Source') . "<td>" . lang('Target') . "<td>" . lang('ON DELETE') . "<td>" . lang('ON UPDATE') . "<td></thead>\n";
foreach ($foreign_keys as $name => $foreign_key) { foreach ($foreign_keys as $name => $foreign_key) {
echo "<tr title='" . h($name) . "'>"; echo "<tr title='" . h($name) . "'>";
echo "<th><i>" . implode("</i>, <i>", array_map('h', $foreign_key["source"])) . "</i>"; 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"]) . "'>" 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"]) . "'>"
. ($foreign_key["db"] != "" ? "<b>" . h($foreign_key["db"]) . "</b>." : "") . ($foreign_key["ns"] != "" ? "<b>" . h($foreign_key["ns"]) . "</b>." : "") . h($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"])
. "</a>" . "</a>"
; ;
echo "(<i>" . implode("</i>, <i>", array_map('h', $foreign_key["target"])) . "</i>)"; echo "(<i>" . implode("</i>, <i>", array_map('Adminer\h', $foreign_key["target"])) . "</i>)";
echo "<td>" . h($foreign_key["on_delete"]); echo "<td>" . h($foreign_key["on_delete"]);
echo "<td>" . h($foreign_key["on_update"]); echo "<td>" . h($foreign_key["on_update"]);
echo '<td><a href="' . h(ME . 'foreign=' . urlencode($TABLE) . '&name=' . urlencode($name)) . '">' . lang('Alter') . '</a>'; echo '<td><a href="' . h(ME . 'foreign=' . urlencode($TABLE) . '&name=' . urlencode($name)) . '">' . lang('Alter') . '</a>';
@@ -60,12 +64,12 @@ if (!is_view($table_status)) {
if (support("check")) { if (support("check")) {
echo "<h3 id='checks'>" . lang('Checks') . "</h3>\n"; echo "<h3 id='checks'>" . lang('Checks') . "</h3>\n";
$check_constraints = check_constraints($TABLE); $check_constraints = $driver->checkConstraints($TABLE);
if ($check_constraints) { if ($check_constraints) {
echo "<table>\n"; echo "<table>\n";
foreach ($check_constraints as $key => $val) { foreach ($check_constraints as $key => $val) {
echo "<tr title='" . h($key) . "'>"; echo "<tr title='" . h($key) . "'>";
echo "<td><code class='jush-$jush'>" . h($val); echo "<td><code class='jush-" . JUSH . "'>" . h($val);
echo "<td><a href='" . h(ME . 'check=' . urlencode($TABLE) . '&name=' . urlencode($key)) . "'>" . lang('Alter') . "</a>"; echo "<td><a href='" . h(ME . 'check=' . urlencode($TABLE) . '&name=' . urlencode($key)) . "'>" . lang('Alter') . "</a>";
echo "\n"; echo "\n";
} }

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$TABLE = $_GET["trigger"]; $TABLE = $_GET["trigger"];
$name = $_GET["name"]; $name = $_GET["name"];
$trigger_options = trigger_options(); $trigger_options = trigger_options();
@@ -8,7 +10,7 @@ if ($_POST) {
if (!$error && in_array($_POST["Timing"], $trigger_options["Timing"]) && in_array($_POST["Event"], $trigger_options["Event"]) && in_array($_POST["Type"], $trigger_options["Type"])) { if (!$error && in_array($_POST["Timing"], $trigger_options["Timing"]) && in_array($_POST["Event"], $trigger_options["Event"]) && in_array($_POST["Type"], $trigger_options["Type"])) {
// don't use drop_create() because there may not be more triggers for the same action // don't use drop_create() because there may not be more triggers for the same action
$on = " ON " . table($TABLE); $on = " ON " . table($TABLE);
$drop = "DROP TRIGGER " . idf_escape($name) . ($jush == "pgsql" ? $on : ""); $drop = "DROP TRIGGER " . idf_escape($name) . (JUSH == "pgsql" ? $on : "");
$location = ME . "table=" . urlencode($TABLE); $location = ME . "table=" . urlencode($TABLE);
if ($_POST["drop"]) { if ($_POST["drop"]) {
query_redirect($drop, $location, lang('Trigger has been dropped.')); query_redirect($drop, $location, lang('Trigger has been dropped.'));
@@ -44,6 +46,8 @@ page_header(($name != "" ? lang('Alter trigger') . ": " . h($name) : lang('Creat
<p><?php textarea("Statement", $row["Statement"]); ?> <p><?php textarea("Statement", $row["Statement"]); ?>
<p> <p>
<input type="submit" value="<?php echo lang('Save'); ?>"> <input type="submit" value="<?php echo lang('Save'); ?>">
<?php if ($name != "") { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $name)); ?><?php } ?> <?php if ($name != "") { ?>
<input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', $name)); ?>
<?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>"> <input type="hidden" name="token" value="<?php echo $token; ?>">
</form> </form>

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$TYPE = $_GET["type"]; $TYPE = $_GET["type"];
$row = $_POST; $row = $_POST;
@@ -22,9 +24,17 @@ if (!$row) {
<p> <p>
<?php <?php
if ($TYPE != "") { if ($TYPE != "") {
$types = $driver->types();
$enums = type_values($types[$TYPE]);
if ($enums) {
echo "<code class='jush-" . JUSH . "'>ENUM (" . h($enums) . ")</code>\n<p>";
}
echo "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . confirm(lang('Drop %s?', $TYPE)) . "\n"; echo "<input type='submit' name='drop' value='" . lang('Drop') . "'>" . confirm(lang('Drop %s?', $TYPE)) . "\n";
} else { } else {
echo "<input name='name' value='" . h($row['name']) . "' autocapitalize='off'>\n"; echo lang('Name') . ": <input name='name' value='" . h($row['name']) . "' autocapitalize='off'>\n";
echo doc_link(array(
'pgsql' => "datatype-enum.html",
), "?");
textarea("as", $row["as"]); textarea("as", $row["as"]);
echo "<p><input type='submit' value='" . lang('Save') . "'>\n"; echo "<p><input type='submit' value='" . lang('Save') . "'>\n";
} }

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$USER = $_GET["user"]; $USER = $_GET["user"];
$privileges = array("" => array("All privileges" => "")); $privileges = array("" => array("All privileges" => ""));
foreach (get_rows("SHOW PRIVILEGES") as $row) { foreach (get_rows("SHOW PRIVILEGES") as $row) {
@@ -84,10 +86,11 @@ if ($_POST && !$error) {
$grant = array_diff($grant, $old_grant); $grant = array_diff($grant, $old_grant);
unset($grants[$object]); unset($grants[$object]);
} }
if (preg_match('~^(.+)\s*(\(.*\))?$~U', $object, $match) && ( if (
preg_match('~^(.+)\s*(\(.*\))?$~U', $object, $match) && (
!grant("REVOKE", $revoke, $match[2], " ON $match[1] FROM $new_user") //! SQL injection !grant("REVOKE", $revoke, $match[2], " ON $match[1] FROM $new_user") //! SQL injection
|| !grant("GRANT", $grant, $match[2], " ON $match[1] TO $new_user") || !grant("GRANT", $grant, $match[2], " ON $match[1] TO $new_user"))
)) { ) {
$error = true; $error = true;
break; break;
} }
@@ -135,7 +138,7 @@ if ($_POST) {
<tr><th><?php echo lang('Server'); ?><td><input name="host" data-maxlength="60" value="<?php echo h($row["host"]); ?>" autocapitalize="off"> <tr><th><?php echo lang('Server'); ?><td><input name="host" data-maxlength="60" value="<?php echo h($row["host"]); ?>" autocapitalize="off">
<tr><th><?php echo lang('Username'); ?><td><input name="user" data-maxlength="80" value="<?php echo h($row["user"]); ?>" autocapitalize="off"> <tr><th><?php echo lang('Username'); ?><td><input name="user" data-maxlength="80" value="<?php echo h($row["user"]); ?>" autocapitalize="off">
<tr><th><?php echo lang('Password'); ?><td><input name="pass" id="pass" value="<?php echo h($row["pass"]); ?>" autocomplete="new-password"> <tr><th><?php echo lang('Password'); ?><td><input name="pass" id="pass" value="<?php echo h($row["pass"]); ?>" autocomplete="new-password">
<?php if (!$row["hashed"]) { echo script("typePassword(qs('#pass'));"); } ?> <?php echo ($row["hashed"] ? "" : script("typePassword(qs('#pass'));")); ?>
<?php echo (min_version(8) ? "" : checkbox("hashed", 1, $row["hashed"], lang('Hashed'), "typePassword(this.form['pass'], this.checked);")); ?> <?php echo (min_version(8) ? "" : checkbox("hashed", 1, $row["hashed"], lang('Hashed'), "typePassword(this.form['pass'], this.checked);")); ?>
</table> </table>
@@ -150,14 +153,16 @@ foreach ($grants as $object => $grant) {
} }
echo "</thead>\n"; echo "</thead>\n";
foreach (array( foreach (
"" => "", array(
"Server Admin" => lang('Server'), "" => "",
"Databases" => lang('Database'), "Server Admin" => lang('Server'),
"Tables" => lang('Table'), "Databases" => lang('Database'),
"Columns" => lang('Column'), "Tables" => lang('Table'),
"Procedures" => lang('Routine'), "Columns" => lang('Column'),
) as $context => $desc) { "Procedures" => lang('Routine'),
) as $context => $desc
) {
foreach ((array) $privileges[$context] as $privilege => $comment) { foreach ((array) $privileges[$context] as $privilege => $comment) {
echo "<tr><td" . ($desc ? ">$desc<td" : " colspan='2'") . ' lang="en" title="' . h($comment) . '">' . h($privilege); echo "<tr><td" . ($desc ? ">$desc<td" : " colspan='2'") . ' lang="en" title="' . h($comment) . '">' . h($privilege);
$i = 0; $i = 0;
@@ -184,6 +189,8 @@ echo "</table>\n";
?> ?>
<p> <p>
<input type="submit" value="<?php echo lang('Save'); ?>"> <input type="submit" value="<?php echo lang('Save'); ?>">
<?php if (isset($_GET["host"])) { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', "$USER@$_GET[host]")); ?><?php } ?> <?php if (isset($_GET["host"])) { ?>
<input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"><?php echo confirm(lang('Drop %s?', "$USER@$_GET[host]")); ?>
<?php } ?>
<input type="hidden" name="token" value="<?php echo $token; ?>"> <input type="hidden" name="token" value="<?php echo $token; ?>">
</form> </form>

View File

@@ -1,4 +1,6 @@
<?php <?php
namespace Adminer;
$status = isset($_GET["status"]); $status = isset($_GET["status"]);
page_header($status ? lang('Status') : lang('Variables')); page_header($status ? lang('Status') : lang('Variables'));
@@ -9,8 +11,8 @@ if (!$variables) {
echo "<table>\n"; echo "<table>\n";
foreach ($variables as $key => $val) { foreach ($variables as $key => $val) {
echo "<tr>"; echo "<tr>";
echo "<th><code class='jush-" . $jush . ($status ? "status" : "set") . "'>" . h($key) . "</code>"; echo "<th><code class='jush-" . JUSH . ($status ? "status" : "set") . "'>" . h($key) . "</code>";
echo "<td>" . h($val); echo "<td>" . nl_br(h($val));
} }
echo "</table>\n"; echo "</table>\n";
} }

Some files were not shown because too many files have changed in this diff Show More