mirror of
https://github.com/vrana/adminer.git
synced 2025-08-09 16:17:48 +02:00
Allow creating generated columns (bug #857)
This commit is contained in:
@@ -48,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);
|
||||||
@@ -155,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -322,6 +322,9 @@ if (!defined('Adminer\DRIVER')) {
|
|||||||
$this->types[lang('Numbers')]["vector"] = 16383;
|
$this->types[lang('Numbers')]["vector"] = 16383;
|
||||||
$this->editFunctions[0]['vector'] = 'string_to_vector';
|
$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) {
|
||||||
@@ -592,8 +595,9 @@ if (!defined('Adminer\DRIVER')) {
|
|||||||
$field = $row["COLUMN_NAME"];
|
$field = $row["COLUMN_NAME"];
|
||||||
$default = $row["COLUMN_DEFAULT"];
|
$default = $row["COLUMN_DEFAULT"];
|
||||||
$type = $row["COLUMN_TYPE"];
|
$type = $row["COLUMN_TYPE"];
|
||||||
|
$extra = $row["EXTRA"];
|
||||||
// https://mariadb.com/kb/en/library/show-columns/, https://github.com/vrana/adminer/pull/359#pullrequestreview-276677186
|
// https://mariadb.com/kb/en/library/show-columns/, https://github.com/vrana/adminer/pull/359#pullrequestreview-276677186
|
||||||
$generated = preg_match('~^(VIRTUAL|PERSISTENT|STORED)~', $row["EXTRA"]);
|
preg_match('~^(VIRTUAL|PERSISTENT|STORED)~', $extra, $generated);
|
||||||
preg_match('~^([^( ]+)(?:\((.+)\))?( unsigned)?( zerofill)?$~', $type, $match);
|
preg_match('~^([^( ]+)(?:\((.+)\))?( unsigned)?( zerofill)?$~', $type, $match);
|
||||||
$return[$field] = array(
|
$return[$field] = array(
|
||||||
"field" => $field,
|
"field" => $field,
|
||||||
@@ -609,13 +613,13 @@ if (!defined('Adminer\DRIVER')) {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
"null" => ($row["IS_NULLABLE"] == "YES"),
|
"null" => ($row["IS_NULLABLE"] == "YES"),
|
||||||
"auto_increment" => ($row["EXTRA"] == "auto_increment"),
|
"auto_increment" => ($extra == "auto_increment"),
|
||||||
"on_update" => (preg_match('~\bon update (\w+)~i', $row["EXTRA"], $match) ? $match[1] : ""), //! available since MySQL 5.1.23
|
"on_update" => (preg_match('~\bon update (\w+)~i', $extra, $match) ? $match[1] : ""), //! available since MySQL 5.1.23
|
||||||
"collation" => $row["COLLATION_NAME"],
|
"collation" => $row["COLLATION_NAME"],
|
||||||
"privileges" => array_flip(explode(",", $row["PRIVILEGES"])),
|
"privileges" => array_flip(explode(",", $row["PRIVILEGES"])),
|
||||||
"comment" => $row["COLUMN_COMMENT"],
|
"comment" => $row["COLUMN_COMMENT"],
|
||||||
"primary" => ($row["COLUMN_KEY"] == "PRI"),
|
"primary" => ($row["COLUMN_KEY"] == "PRI"),
|
||||||
"generated" => $generated,
|
"generated" => ($generated[1] == "PERSISTENT" ? "STORED" : $generated[1]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return $return;
|
return $return;
|
||||||
@@ -788,10 +792,16 @@ if (!defined('Adminer\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) : "")
|
||||||
|
@@ -229,6 +229,9 @@ if (isset($_GET["pgsql"])) {
|
|||||||
"char|text" => "||",
|
"char|text" => "||",
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
if (min_version(12, 0, $connection)) {
|
||||||
|
$this->generated = array("STORED");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setUserTypes($types) {
|
function setUserTypes($types) {
|
||||||
@@ -441,7 +444,7 @@ ORDER BY a.attnum") as $row
|
|||||||
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");
|
$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);
|
||||||
@@ -576,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]";
|
||||||
|
@@ -36,6 +36,7 @@ abstract class SqlDriver {
|
|||||||
var $onActions = "RESTRICT|NO ACTION|CASCADE|SET NULL|SET DEFAULT"; ///< @var string used in foreign_keys()
|
var $onActions = "RESTRICT|NO ACTION|CASCADE|SET NULL|SET DEFAULT"; ///< @var string used in foreign_keys()
|
||||||
var $inout = "IN|OUT|INOUT";
|
var $inout = "IN|OUT|INOUT";
|
||||||
var $enumLength = "'(?:''|[^'\\\\]|\\\\.)*'";
|
var $enumLength = "'(?:''|[^'\\\\]|\\\\.)*'";
|
||||||
|
var $generated = array();
|
||||||
|
|
||||||
/** Create object for performing database operations
|
/** Create object for performing database operations
|
||||||
* @param Db
|
* @param Db
|
||||||
|
@@ -302,11 +302,17 @@ function process_field($field, $type_field) {
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
function default_value($field) {
|
function default_value($field) {
|
||||||
|
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 (
|
||||||
? q($default) : str_ireplace("current_timestamp()", "CURRENT_TIMESTAMP", (JUSH == "sqlite" ? "($default)" : $default)))
|
$default === null ? ""
|
||||||
);
|
: (in_array($generated, $driver->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
|
||||||
@@ -380,7 +386,12 @@ function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = arra
|
|||||||
?>
|
?>
|
||||||
<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 echo ($field["auto_increment"] ? " checked" : ""); ?> 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>";
|
||||||
|
@@ -290,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,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;
|
||||||
@@ -422,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));
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
Adminer dev:
|
Adminer dev:
|
||||||
Speed up with disabled output buffering
|
Speed up with disabled output buffering
|
||||||
|
Allow creating generated columns (bug #857)
|
||||||
Don't autofocus computed fields in insert form
|
Don't autofocus computed fields in insert form
|
||||||
Skip generated columns in multi-edit (bug #882)
|
Skip generated columns in multi-edit (bug #882)
|
||||||
MySQL: Display generated value in table structure
|
MySQL: Display generated value in table structure
|
||||||
|
Reference in New Issue
Block a user