]> git.joonet.de Git - adminer.git/commitdiff
SQLite: Support CHECK constraint
authorJakub Vrana <jakub@vrana.cz>
Wed, 26 Feb 2025 10:59:50 +0000 (11:59 +0100)
committerJakub Vrana <jakub@vrana.cz>
Wed, 26 Feb 2025 11:20:37 +0000 (12:20 +0100)
adminer/check.inc.php
adminer/drivers/sqlite.inc.php
adminer/include/driver.inc.php
adminer/include/editing.inc.php
adminer/table.inc.php
changes.txt
compile.php

index c6724dbce0645d934403af0a6bfc1d458170409d..e1f6961e3034720c6816c92511fd668acab2c0ae 100644 (file)
@@ -4,9 +4,13 @@ $name = $_GET["name"];
 $row = $_POST;
 
 if ($row && !$error) {
-       $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
+       if ($jush == "sqlite") {
+               $result = recreate_table($TABLE, $TABLE, array(), array(), array(), 0, array(), $name, ($row["drop"] ? "" : $row["clause"]));
+       } 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(
                ME . "table=" . urlencode($TABLE),
@@ -18,18 +22,24 @@ if ($row && !$error) {
 page_header(($name != "" ? lang('Alter check') . ": " . h($name) : lang('Create check')), $error, array("table" => $TABLE));
 
 if (!$row) {
-       $checks = check_constraints($TABLE);
+       $checks = $driver->checkConstraints($TABLE);
        $row = array("name" => $name, "clause" => $checks[$name]);
 }
 ?>
 
 <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
+if ($jush != "sqlite") {
+       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><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 } ?>
index 5408806af4ed9aa622a042ab6e6160b8f3c7b8d5..bd2921f7df4d8810981bd0dd48ac39f351e73396 100644 (file)
@@ -227,6 +227,11 @@ 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]);
+               }
+
        }
 
 
@@ -523,8 +528,20 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
                return true;
        }
 
-       function recreate_table($table, $name, $fields, $originals, $foreign, $auto_increment = 0, $indexes = array()) {
-               global $connection;
+       /** Recreate table
+       * @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 [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 (!$fields) {
                                foreach (fields($table) as $key => $field) {
@@ -585,6 +602,14 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
                        $fields[$key] = "  " . implode($field);
                }
                $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);
                if (!queries("CREATE TABLE " . table($temp_name) . " (\n" . implode(",\n", $fields) . "\n)")) {
                        // implicit ROLLBACK to not overwrite $connection->error
@@ -785,7 +810,7 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
        }
 
        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() {
index 394ab635161bd4cb16c730807893fe7520649c1c..9bb21e35badee7ac8935dbc3f68f735324108736 100644 (file)
@@ -200,4 +200,18 @@ function get_driver($id) {
                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
+       }
+
 }
index 53c9b159fa6857edc02b74ecd378041cf1a392b6..337669888b04de61a0be30438ceb163c8a158af1 100644 (file)
@@ -531,20 +531,6 @@ function create_routine($routine, $row) {
        ;
 }
 
-/** 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
 * @param string
 * @return string
index 76f1d5cbb26c25bc8d4e8655544b02dfa3df05ce..d2af40c2b1a189b5c225de5e64e85ed9f5f4dbdb 100644 (file)
@@ -60,7 +60,7 @@ if (!is_view($table_status)) {
 
        if (support("check")) {
                echo "<h3 id='checks'>" . lang('Checks') . "</h3>\n";
-               $check_constraints = check_constraints($TABLE);
+               $check_constraints = $driver->checkConstraints($TABLE);
                if ($check_constraints) {
                        echo "<table>\n";
                        foreach ($check_constraints as $key => $val) {
index 08adefbb351a3ffac0e11043b302507dff77f887..c36a62221676c815184df1a870cfbba2b77f90d2 100644 (file)
@@ -1,4 +1,5 @@
 Adminer-4.17.2-dev:
+SQLite: Support CHECK constraint
 SQLite: Add command Check tables
 SQLite: Display all rows of variable values
 MongoDB: Remove support for deprecated extension mongo
index e3cd1f56ac4e72810958b56940462a9d30e7cbf6..80b18969123c33801d8392ec9f482257c4cd6792 100755 (executable)
@@ -67,7 +67,6 @@ header("Cache-Control: immutable");
                        ); //! respect context (extension, class)
                        $functions = array_combine($matches[1], $matches[0]);
                        $requires = array(
-                               "check" => array("check_constraints"),
                                "copy" => array("copy_tables"),
                                "database" => array("create_database", "rename_database", "drop_databases"),
                                "dump" => array("use_sql", "create_sql", "truncate_sql", "trigger_sql"),