diff --git a/adminer/create.inc.php b/adminer/create.inc.php index e5bdc4d9..a382cfde 100644 --- a/adminer/create.inc.php +++ b/adminer/create.inc.php @@ -23,10 +23,12 @@ if ($_POST && !$error && !$_POST["add"] && !$_POST["drop_col"] && !$_POST["up"] query_redirect("DROP TABLE " . table($TABLE), substr(ME, 0, -1), lang('Table has been dropped.')); } else { $fields = array(); + $all_fields = array(); + $use_all_fields = false; $foreign = array(); ksort($_POST["fields"]); $orig_field = reset($orig_fields); - $after = "FIRST"; + $after = " FIRST"; foreach ($_POST["fields"] as $key => $field) { $foreign_key = $foreign_keys[$field["type"]]; $type_field = ($foreign_key !== null ? $referencable_primary[$foreign_key] : $field); //! can collide with user defined type @@ -43,18 +45,26 @@ if ($_POST && !$error && !$_POST["add"] && !$_POST["drop_col"] && !$_POST["up"] $field["auto_increment"] = true; } $process_field = process_field($field, $type_field); + $all_fields[] = array($field["orig"], $process_field, $after); if ($process_field != process_field($orig_field, $orig_field)) { $fields[] = array($field["orig"], $process_field, $after); + if ($field["orig"] != "" || $after) { + $use_all_fields = true; + } } if ($foreign_key !== null) { - $foreign[idf_escape($field["field"])] = ($TABLE != "" ? "ADD" : " ") . " FOREIGN KEY (" . idf_escape($field["field"]) . ") REFERENCES " . table($foreign_keys[$field["type"]]) . " (" . idf_escape($type_field["field"]) . ")" . (ereg("^($on_actions)\$", $field["on_delete"]) ? " ON DELETE $field[on_delete]" : ""); + $foreign[idf_escape($field["field"])] = ($TABLE != "" && $jush != "sqlite" ? "ADD" : " ") . " FOREIGN KEY (" . idf_escape($field["field"]) . ") REFERENCES " . table($foreign_keys[$field["type"]]) . " (" . idf_escape($type_field["field"]) . ")" . (ereg("^($on_actions)\$", $field["on_delete"]) ? " ON DELETE $field[on_delete]" : ""); } - $after = "AFTER " . idf_escape($field["field"]); + $after = " AFTER " . idf_escape($field["field"]); } elseif ($field["orig"] != "") { + $use_all_fields = true; $fields[] = array($field["orig"]); } if ($field["orig"] != "") { $orig_field = next($orig_fields); + if (!$orig_field) { + $after = ""; + } } } $partitioning = ""; @@ -82,7 +92,7 @@ if ($_POST && !$error && !$_POST["add"] && !$_POST["drop_col"] && !$_POST["up"] queries_redirect(ME . "table=" . urlencode($name), $message, alter_table( $TABLE, $name, - $fields, + ($jush == "sqlite" && ($use_all_fields || $foreign) ? $all_fields : $fields), $foreign, $_POST["Comment"], ($_POST["Engine"] && $_POST["Engine"] != $orig_status["Engine"] ? $_POST["Engine"] : ""), diff --git a/adminer/drivers/mysql.inc.php b/adminer/drivers/mysql.inc.php index 392a6712..72a393ae 100644 --- a/adminer/drivers/mysql.inc.php +++ b/adminer/drivers/mysql.inc.php @@ -603,7 +603,7 @@ if (!defined("DRIVER")) { $alter = array(); foreach ($fields as $field) { $alter[] = ($field[1] - ? ($table != "" ? ($field[0] != "" ? "CHANGE " . idf_escape($field[0]) : "ADD") : " ") . " " . implode($field[1]) . ($table != "" ? " $field[2]" : "") + ? ($table != "" ? ($field[0] != "" ? "CHANGE " . idf_escape($field[0]) : "ADD") : " ") . " " . implode($field[1]) . ($table != "" ? $field[2] : "") : "DROP " . idf_escape($field[0]) ); } diff --git a/adminer/drivers/sqlite.inc.php b/adminer/drivers/sqlite.inc.php index 1f21b14c..c471f939 100644 --- a/adminer/drivers/sqlite.inc.php +++ b/adminer/drivers/sqlite.inc.php @@ -267,7 +267,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) { function fk_support($table_status) { global $connection; - return $_GET["create"] == "" && !$connection->result("SELECT sqlite_compileoption_used('OMIT_FOREIGN_KEY')"); + return !$connection->result("SELECT sqlite_compileoption_used('OMIT_FOREIGN_KEY')"); } function fields($table) { @@ -402,14 +402,90 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) { } function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) { - $alter = array(); + $use_all_fields = ($table == "" || $foreign); foreach ($fields as $field) { - if ($field[1]) { - $alter[] = ($table != "" && $field[0] == "" ? "ADD " : " ") . implode($field[1]); + if ($field[0] != "" || !$field[1] || $field[2]) { + $use_all_fields = true; + break; } } - $alter = array_merge($alter, $foreign); - if ($table != "") { + $alter = array(); + $originals = array(); + $primary_key = false; + foreach ($fields as $field) { + if ($field[1]) { + if ($field[1][6]) { + $primary_key = true; + } + $alter[] = ($use_all_fields ? " " : "ADD ") . implode($field[1]); + if ($field[0] != "") { + $originals[$field[0]] = $field[1][0]; + } + } + } + if ($use_all_fields) { + if ($table != "") { + queries("BEGIN"); + foreach (foreign_keys($table) as $foreign_key) { + $columns = array(); + foreach ($foreign_key["source"] as $column) { + if (!$originals[$column]) { + continue 2; + } + $columns[] = $originals[$column]; + } + $foreign[] = " FOREIGN KEY (" . implode(", ", $columns) . ") REFERENCES " + . table($foreign_key["table"]) + . " (" . implode(", ", array_map('idf_escape', $foreign_key["target"])) + . ") ON DELETE $foreign_key[on_delete] ON UPDATE $foreign_key[on_update]" + ; + } + $indexes = array(); + foreach (indexes($table) as $key_name => $index) { + $columns = array(); + foreach ($index["columns"] as $column) { + if (!$originals[$column]) { + continue 2; + } + $columns[] = $originals[$column]; + } + $columns = "(" . implode(", ", $columns) . ")"; + if ($index["type"] != "PRIMARY") { + $indexes[] = array($index["type"], $key_name, $columns); + } elseif (!$primary_key) { + $foreign[] = " PRIMARY KEY $columns"; + } + } + } + $alter = array_merge($alter, $foreign); + if (!queries("CREATE TABLE " . table($table != "" ? "adminer_$name" : $name) . " (\n" . implode(",\n", $alter) . "\n)")) { + // implicit ROLLBACK to not overwrite $connection->error + return false; + } + if ($table != "") { + if ($originals && !queries("INSERT INTO " . table("adminer_$name") . " (" . implode(", ", $originals) . ") SELECT " . implode(", ", array_map('idf_escape', array_keys($originals))) . " FROM " . table($table))) { + return false; + } + $triggers = array(); + foreach (triggers($table) as $trigger_name => $timing_event) { + $trigger = trigger($trigger_name); + $triggers[] = "CREATE TRIGGER " . idf_escape($trigger_name) . " " . implode(" ", $timing_event) . " ON " . table($name) . "\n$trigger[Statement]"; + } + if (!queries("DROP TABLE " . table($table))) { // drop before creating indexes and triggers to allow using old names + return false; + } + queries("ALTER TABLE " . table("adminer_$name") . " RENAME TO " . table($name)); + if (!alter_indexes($name, $indexes)) { + return false; + } + foreach ($triggers as $trigger) { + if (!queries($trigger)) { + return false; + } + } + queries("COMMIT"); + } + } else { foreach ($alter as $val) { if (!queries("ALTER TABLE " . table($table) . " $val")) { return false; @@ -418,8 +494,6 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) { if ($table != $name && !queries("ALTER TABLE " . table($table) . " RENAME TO " . table($name))) { return false; } - } elseif (!queries("CREATE TABLE " . table($name) . " (\n" . implode(",\n", $alter) . "\n)")) { - return false; } if ($auto_increment) { queries("UPDATE sqlite_sequence SET seq = $auto_increment WHERE name = " . q($name)); // ignores error @@ -567,7 +641,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) { } function support($feature) { - return ereg('^(view|trigger|variables|status|dump)$', $feature); + return ereg('^(view|trigger|variables|status|dump|move_col|drop_col)$', $feature); } $jush = "sqlite"; diff --git a/changes.txt b/changes.txt index a43333e1..0c5d365a 100644 --- a/changes.txt +++ b/changes.txt @@ -1,3 +1,6 @@ +Adminer 3.4.1-dev: +SQLite: Full alter table + Adminer 3.4.0 (released 2012-06-30): Link to descending order Shift+click on checkbox to select consecutive rows