diff --git a/adminer/dump.inc.php b/adminer/dump.inc.php index d4d33934..57fe60bc 100644 --- a/adminer/dump.inc.php +++ b/adminer/dump.inc.php @@ -8,7 +8,7 @@ if ($_POST) { } cookie("adminer_export", substr($cookie, 1)); $ext = dump_headers(($TABLE != "" ? $TABLE : DB), (DB == "" || count((array) $_POST["tables"] + (array) $_POST["data"]) > 1)); - $is_sql = ($_POST["format"] == "sql"); + $is_sql = ereg('sql', $_POST["format"]); if ($is_sql) { echo "-- Adminer $VERSION " . $drivers[DRIVER] . " dump @@ -29,20 +29,18 @@ SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; } } foreach ((array) $databases as $db) { + $adminer->dumpDatabase($db); if ($connection->select_db($db)) { if ($is_sql && ereg('CREATE', $style) && ($create = $connection->result("SHOW CREATE DATABASE " . idf_escape($db), 1))) { if ($style == "DROP+CREATE") { echo "DROP DATABASE IF EXISTS " . idf_escape($db) . ";\n"; } - echo ($style == "CREATE+ALTER" ? preg_replace('~^CREATE DATABASE ~', '\\0IF NOT EXISTS ', $create) : $create) . ";\n"; + echo "$create;\n"; } if ($is_sql) { if ($style) { echo use_sql($db) . ";\n\n"; } - if (in_array("CREATE+ALTER", array($style, $_POST["table_style"]))) { - echo "SET @adminer_alter = '';\n\n"; - } $out = ""; if ($_POST["routines"]) { foreach (array("FUNCTION", "PROCEDURE") as $routine) { @@ -97,46 +95,6 @@ SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; echo pack("x512"); } } - - if ($style == "CREATE+ALTER" && $is_sql) { - // drop old tables - $query = "SELECT TABLE_NAME, ENGINE, TABLE_COLLATION, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE()"; - echo "DELIMITER ;; -CREATE PROCEDURE adminer_alter (INOUT alter_command text) BEGIN - DECLARE _table_name, _engine, _table_collation varchar(64); - DECLARE _table_comment varchar(64); - DECLARE done bool DEFAULT 0; - DECLARE tables CURSOR FOR $query; - DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; - OPEN tables; - REPEAT - FETCH tables INTO _table_name, _engine, _table_collation, _table_comment; - IF NOT done THEN - CASE _table_name"; - foreach (get_rows($query) as $row) { - $comment = q($row["ENGINE"] == "InnoDB" ? preg_replace('~(?:(.+); )?InnoDB free: .*~', '\\1', $row["TABLE_COMMENT"]) : $row["TABLE_COMMENT"]); - echo " - WHEN " . q($row["TABLE_NAME"]) . " THEN - " . (isset($row["ENGINE"]) ? "IF _engine != '$row[ENGINE]' OR _table_collation != '$row[TABLE_COLLATION]' OR _table_comment != $comment THEN - ALTER TABLE " . idf_escape($row["TABLE_NAME"]) . " ENGINE=$row[ENGINE] COLLATE=$row[TABLE_COLLATION] COMMENT=$comment; - END IF" : "BEGIN END") . ";"; - } - echo " - ELSE - SET alter_command = CONCAT(alter_command, 'DROP TABLE `', REPLACE(_table_name, '`', '``'), '`;\\n'); - END CASE; - END IF; - UNTIL done END REPEAT; - CLOSE tables; -END;; -DELIMITER ; -CALL adminer_alter(@adminer_alter); -DROP PROCEDURE adminer_alter; -"; - } - if (in_array("CREATE+ALTER", array($style, $_POST["table_style"])) && $is_sql) { - echo "SELECT @adminer_alter;\n"; - } } } if ($is_sql) { @@ -154,9 +112,7 @@ page_header(lang('Export'), "", ($_GET["export"] != "" ? array("table" => $_GET[ $db_style = array('', 'USE', 'DROP+CREATE', 'CREATE'); $table_style = array('', 'DROP+CREATE', 'CREATE'); $data_style = array('', 'TRUNCATE+INSERT', 'INSERT'); -if ($jush == "sql") { - $db_style[] = 'CREATE+ALTER'; - $table_style[] = 'CREATE+ALTER'; +if ($jush == "sql") { //! use insert_update() in all drivers $data_style[] = 'INSERT+UPDATE'; } parse_str($_COOKIE["adminer_export"], $row); diff --git a/adminer/include/adminer.inc.php b/adminer/include/adminer.inc.php index ba77b5f7..7ea16c64 100644 --- a/adminer/include/adminer.inc.php +++ b/adminer/include/adminer.inc.php @@ -585,6 +585,13 @@ username.form['auth[driver]'].onchange(); return array('sql' => 'SQL', 'csv' => 'CSV,', 'csv;' => 'CSV;', 'tsv' => 'TSV'); } + /** Export database structure + * @param string + * @return null prints data + */ + function dumpDatabase($db) { + } + /** Export table structure * @param string * @param string @@ -606,78 +613,7 @@ username.form['auth[driver]'].onchange(); if ($is_view) { $create = remove_definer($create); } - echo ($style != "CREATE+ALTER" ? $create : ($is_view ? substr_replace($create, " OR REPLACE", 6, 0) : substr_replace($create, " IF NOT EXISTS", 12, 0))) . ";\n\n"; - } - if ($style == "CREATE+ALTER" && !$is_view) { - // create procedure which iterates over original columns and adds new and removes old - $query = "SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, COLLATION_NAME, COLUMN_TYPE, EXTRA, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = " . q($table) . " ORDER BY ORDINAL_POSITION"; - echo "DELIMITER ;; -CREATE PROCEDURE adminer_alter (INOUT alter_command text) BEGIN - DECLARE _column_name, _collation_name, after varchar(64) DEFAULT ''; - DECLARE _column_type, _column_default text; - DECLARE _is_nullable char(3); - DECLARE _extra varchar(30); - DECLARE _column_comment varchar(255); - DECLARE done, set_after bool DEFAULT 0; - DECLARE add_columns text DEFAULT '"; - $fields = array(); - $after = ""; - foreach (get_rows($query) as $row) { - $default = $row["COLUMN_DEFAULT"]; - $row["default"] = ($default !== null ? q($default) : "NULL"); - $row["after"] = q($after); //! rgt AFTER lft, lft AFTER id doesn't work - $row["alter"] = escape_string(idf_escape($row["COLUMN_NAME"]) - . " $row[COLUMN_TYPE]" - . ($row["COLLATION_NAME"] ? " COLLATE $row[COLLATION_NAME]" : "") - . ($default !== null ? " DEFAULT " . ($default == "CURRENT_TIMESTAMP" ? $default : $row["default"]) : "") - . ($row["IS_NULLABLE"] == "YES" ? "" : " NOT NULL") - . ($row["EXTRA"] ? " $row[EXTRA]" : "") - . ($row["COLUMN_COMMENT"] ? " COMMENT " . q($row["COLUMN_COMMENT"]) : "") - . ($after ? " AFTER " . idf_escape($after) : " FIRST") - ); - echo ", ADD $row[alter]"; - $fields[] = $row; - $after = $row["COLUMN_NAME"]; - } - echo "'; - DECLARE columns CURSOR FOR $query; - DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; - SET @alter_table = ''; - OPEN columns; - REPEAT - FETCH columns INTO _column_name, _column_default, _is_nullable, _collation_name, _column_type, _extra, _column_comment; - IF NOT done THEN - SET set_after = 1; - CASE _column_name"; - foreach ($fields as $row) { - echo " - WHEN " . q($row["COLUMN_NAME"]) . " THEN - SET add_columns = REPLACE(add_columns, ', ADD $row[alter]', IF( - _column_default <=> $row[default] AND _is_nullable = '$row[IS_NULLABLE]' AND _collation_name <=> " . (isset($row["COLLATION_NAME"]) ? "'$row[COLLATION_NAME]'" : "NULL") . " AND _column_type = " . q($row["COLUMN_TYPE"]) . " AND _extra = '$row[EXTRA]' AND _column_comment = " . q($row["COLUMN_COMMENT"]) . " AND after = $row[after] - , '', ', MODIFY $row[alter]'));" - ; //! don't replace in comment - } - echo " - ELSE - SET @alter_table = CONCAT(@alter_table, ', DROP ', _column_name); - SET set_after = 0; - END CASE; - IF set_after THEN - SET after = _column_name; - END IF; - END IF; - UNTIL done END REPEAT; - CLOSE columns; - IF @alter_table != '' OR add_columns != '' THEN - SET alter_command = CONCAT(alter_command, 'ALTER TABLE " . table($table) . "', SUBSTR(CONCAT(add_columns, @alter_table), 2), ';\\n'); - END IF; -END;; -DELIMITER ; -CALL adminer_alter(@adminer_alter); -DROP PROCEDURE adminer_alter; - -"; - //! indexes + echo "$create;\n\n"; } } } @@ -766,7 +702,7 @@ DROP PROCEDURE adminer_alter; */ function dumpHeaders($identifier, $multi_table = false) { $output = $_POST["output"]; - $ext = ($_POST["format"] == "sql" ? "sql" : ($multi_table ? "tar" : "csv")); // multiple CSV packed to TAR + $ext = (ereg('sql', $_POST["format"]) ? "sql" : ($multi_table ? "tar" : "csv")); // multiple CSV packed to TAR header("Content-Type: " . ($output == "bz2" ? "application/x-bzip" : ($output == "gz" ? "application/x-gzip" : diff --git a/adminer/plugin.php b/adminer/plugin.php index 0e94373c..d6a7f9a3 100644 --- a/adminer/plugin.php +++ b/adminer/plugin.php @@ -14,6 +14,7 @@ function adminer_object() { new AdminerDumpJson, new AdminerDumpZip, new AdminerDumpXml, + new AdminerDumpAlter, //~ new AdminerSqlLog("past-" . rtrim(`git describe --tags --abbrev=0`) . ".sql"), //~ new AdminerEditCalendar("\n\n\n\n\n\n\n\n\n", "../externals/jquery-ui/ui/i18n/jquery.ui.datepicker-%s.js"), //~ new AdminerTinymce("../externals/tinymce/jscripts/tiny_mce/tiny_mce_dev.js"), diff --git a/changes.txt b/changes.txt index 159945c2..d3fe1b36 100644 --- a/changes.txt +++ b/changes.txt @@ -7,6 +7,7 @@ Stay on the same page after deleting rows (bug #3605845) Handle max_input_vars Disable autocapitalize in identifiers on mobile browsers MySQL: Compatibility with MySQL 5.6 +MySQL: Move ALTER export to plugin SQLite: Export indexes Adminer 3.6.3 (released 2013-01-23): diff --git a/editor/include/adminer.inc.php b/editor/include/adminer.inc.php index a376eca1..b2e9235d 100644 --- a/editor/include/adminer.inc.php +++ b/editor/include/adminer.inc.php @@ -498,6 +498,9 @@ ORDER BY ORDINAL_POSITION", null, "") as $row) { //! requires MySQL 5 return array('csv' => 'CSV,', 'csv;' => 'CSV;', 'tsv' => 'TSV'); } + function dumpDatabase($db) { + } + function dumpTable() { echo "\xef\xbb\xbf"; // UTF-8 byte order mark } diff --git a/plugins/dump-alter.php b/plugins/dump-alter.php new file mode 100644 index 00000000..5f74b9ec --- /dev/null +++ b/plugins/dump-alter.php @@ -0,0 +1,151 @@ + 'Alter'); + } + } + + function _database() { + // drop old tables + $query = "SELECT TABLE_NAME, ENGINE, TABLE_COLLATION, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE()"; + echo "DELIMITER ;; +CREATE PROCEDURE adminer_alter (INOUT alter_command text) BEGIN + DECLARE _table_name, _engine, _table_collation varchar(64); + DECLARE _table_comment varchar(64); + DECLARE done bool DEFAULT 0; + DECLARE tables CURSOR FOR $query; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; + OPEN tables; + REPEAT + FETCH tables INTO _table_name, _engine, _table_collation, _table_comment; + IF NOT done THEN + CASE _table_name"; + foreach (get_rows($query) as $row) { + $comment = q($row["ENGINE"] == "InnoDB" ? preg_replace('~(?:(.+); )?InnoDB free: .*~', '\\1', $row["TABLE_COMMENT"]) : $row["TABLE_COMMENT"]); + echo " + WHEN " . q($row["TABLE_NAME"]) . " THEN + " . (isset($row["ENGINE"]) ? "IF _engine != '$row[ENGINE]' OR _table_collation != '$row[TABLE_COLLATION]' OR _table_comment != $comment THEN + ALTER TABLE " . idf_escape($row["TABLE_NAME"]) . " ENGINE=$row[ENGINE] COLLATE=$row[TABLE_COLLATION] COMMENT=$comment; + END IF" : "BEGIN END") . ";"; + } + echo " + ELSE + SET alter_command = CONCAT(alter_command, 'DROP TABLE `', REPLACE(_table_name, '`', '``'), '`;\\n'); + END CASE; + END IF; + UNTIL done END REPEAT; + CLOSE tables; +END;; +DELIMITER ; +CALL adminer_alter(@adminer_alter); +DROP PROCEDURE adminer_alter; + +SELECT @adminer_alter; +"; + } + + function dumpDatabase($db) { + static $first = true; + if ($_POST["format"] == "sql_alter") { + if ($first) { + $first = false; + echo "SET @adminer_alter = '';\n\n"; + register_shutdown_function(array($this, '_database')); + } else { + $this->_database(); + } + return true; + } + } + + function dumpTable($table, $style, $is_view = false) { + if ($_POST["format"] == "sql_alter") { + $create = create_sql($table, $_POST["auto_increment"]); + if ($is_view) { + echo substr_replace($create, " OR REPLACE", 6, 0) . ";\n\n"; + } else { + echo substr_replace($create, " IF NOT EXISTS", 12, 0) . ";\n\n"; + // create procedure which iterates over original columns and adds new and removes old + $query = "SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, COLLATION_NAME, COLUMN_TYPE, EXTRA, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = " . q($table) . " ORDER BY ORDINAL_POSITION"; + echo "DELIMITER ;; +CREATE PROCEDURE adminer_alter (INOUT alter_command text) BEGIN + DECLARE _column_name, _collation_name, after varchar(64) DEFAULT ''; + DECLARE _column_type, _column_default text; + DECLARE _is_nullable char(3); + DECLARE _extra varchar(30); + DECLARE _column_comment varchar(255); + DECLARE done, set_after bool DEFAULT 0; + DECLARE add_columns text DEFAULT '"; + $fields = array(); + $after = ""; + foreach (get_rows($query) as $row) { + $default = $row["COLUMN_DEFAULT"]; + $row["default"] = ($default !== null ? q($default) : "NULL"); + $row["after"] = q($after); //! rgt AFTER lft, lft AFTER id doesn't work + $row["alter"] = escape_string(idf_escape($row["COLUMN_NAME"]) + . " $row[COLUMN_TYPE]" + . ($row["COLLATION_NAME"] ? " COLLATE $row[COLLATION_NAME]" : "") + . ($default !== null ? " DEFAULT " . ($default == "CURRENT_TIMESTAMP" ? $default : $row["default"]) : "") + . ($row["IS_NULLABLE"] == "YES" ? "" : " NOT NULL") + . ($row["EXTRA"] ? " $row[EXTRA]" : "") + . ($row["COLUMN_COMMENT"] ? " COMMENT " . q($row["COLUMN_COMMENT"]) : "") + . ($after ? " AFTER " . idf_escape($after) : " FIRST") + ); + echo ", ADD $row[alter]"; + $fields[] = $row; + $after = $row["COLUMN_NAME"]; + } + echo "'; + DECLARE columns CURSOR FOR $query; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; + SET @alter_table = ''; + OPEN columns; + REPEAT + FETCH columns INTO _column_name, _column_default, _is_nullable, _collation_name, _column_type, _extra, _column_comment; + IF NOT done THEN + SET set_after = 1; + CASE _column_name"; + foreach ($fields as $row) { + echo " + WHEN " . q($row["COLUMN_NAME"]) . " THEN + SET add_columns = REPLACE(add_columns, ', ADD $row[alter]', IF( + _column_default <=> $row[default] AND _is_nullable = '$row[IS_NULLABLE]' AND _collation_name <=> " . (isset($row["COLLATION_NAME"]) ? "'$row[COLLATION_NAME]'" : "NULL") . " AND _column_type = " . q($row["COLUMN_TYPE"]) . " AND _extra = '$row[EXTRA]' AND _column_comment = " . q($row["COLUMN_COMMENT"]) . " AND after = $row[after] + , '', ', MODIFY $row[alter]'));" + ; //! don't replace in comment + } + echo " + ELSE + SET @alter_table = CONCAT(@alter_table, ', DROP ', _column_name); + SET set_after = 0; + END CASE; + IF set_after THEN + SET after = _column_name; + END IF; + END IF; + UNTIL done END REPEAT; + CLOSE columns; + IF @alter_table != '' OR add_columns != '' THEN + SET alter_command = CONCAT(alter_command, 'ALTER TABLE " . table($table) . "', SUBSTR(CONCAT(add_columns, @alter_table), 2), ';\\n'); + END IF; +END;; +DELIMITER ; +CALL adminer_alter(@adminer_alter); +DROP PROCEDURE adminer_alter; + +"; + //! indexes + } + return true; + } + } + +} diff --git a/plugins/plugin.php b/plugins/plugin.php index 6c3233be..8762330d 100644 --- a/plugins/plugin.php +++ b/plugins/plugin.php @@ -301,6 +301,11 @@ class AdminerPlugin extends Adminer { return $this->_applyPlugin(__FUNCTION__, $args); } + function dumpDatabase() { + $args = func_get_args(); + return $this->_applyPlugin(__FUNCTION__, $args); + } + function dumpTable() { $args = func_get_args(); return $this->_applyPlugin(__FUNCTION__, $args);