]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - lib/mysqlschema.php
Misses this file to merge. I like the comments.
[quix0rs-gnu-social.git] / lib / mysqlschema.php
index 400a7ee598f130e4d343f7bab754ade350008425..f1fc0f46ecd5c600fa12c4d4e128387288718ac1 100644 (file)
@@ -96,18 +96,14 @@ class MysqlSchema extends Schema
 
             // warning -- 'unsigned' attr on numbers isn't given in DATA_TYPE and friends.
             // It is stuck in on COLUMN_TYPE though (eg 'bigint(20) unsigned')
-            list($type, $size) = $this->reverseMapType($row['DATA_TYPE']);
-            $field['type'] = $type;
-            if ($size !== null) {
-                $field['size'] = $size;
-            }
+            $field['type'] = $type = $row['DATA_TYPE'];
 
             if ($type == 'char' || $type == 'varchar') {
                 if ($row['CHARACTER_MAXIMUM_LENGTH'] !== null) {
                     $field['length'] = intval($row['CHARACTER_MAXIMUM_LENGTH']);
                 }
             }
-            if ($type == 'numeric') {
+            if ($type == 'decimal') {
                 // Other int types may report these values, but they're irrelevant.
                 // Just ignore them!
                 if ($row['NUMERIC_PRECISION'] !== null) {
@@ -121,9 +117,14 @@ class MysqlSchema extends Schema
                 $field['not null'] = true;
             }
             if ($row['COLUMN_DEFAULT'] !== null) {
-                $field['default'] = $row['COLUMN_DEFAULT'];
-                if ($this->isNumericType($type)) {
-                    $field['default'] = intval($field['default']);
+                // Hack for timestamp cols
+                if ($type == 'timestamp' && $row['COLUMN_DEFAULT'] == 'CURRENT_TIMESTAMP') {
+                    // skip
+                } else {
+                    $field['default'] = $row['COLUMN_DEFAULT'];
+                    if ($this->isNumericType($type)) {
+                        $field['default'] = intval($field['default']);
+                    }
                 }
             }
             if ($row['COLUMN_KEY'] !== null) {
@@ -137,7 +138,7 @@ class MysqlSchema extends Schema
             $extra = $row['EXTRA'];
             if ($extra) {
                 if (preg_match('/(^|\s)auto_increment(\s|$)/i', $extra)) {
-                    $field['type'] = 'serial';
+                    $field['auto_increment'] = true;
                 }
                 // $row['EXTRA'] may contain 'on update CURRENT_TIMESTAMP'
                 // ^ ...... how to specify?
@@ -243,16 +244,42 @@ class MysqlSchema extends Schema
         return $this->fetchQueryData($sql);
     }
 
+    /**
+     * Append an SQL statement with an index definition for a full-text search
+     * index over one or more columns on a table.
+     *
+     * @param array $statements
+     * @param string $table
+     * @param string $name
+     * @param array $def
+     */
+    function appendCreateFulltextIndex(array &$statements, $table, $name, array $def)
+    {
+        $statements[] = "CREATE FULLTEXT INDEX $name ON $table " . $this->buildIndexList($def);
+    }
+
     /**
      * Close out a 'create table' SQL statement.
      *
      * @param string $name
      * @param array $def
      * @return string;
+     *
+     * @fixme ENGINE may need to be set differently in some cases,
+     * such as to support fulltext index.
      */
     function endCreateTable($name, array $def)
     {
-        return ") ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin";
+        $engine = $this->preferredEngine($def);
+        return ") ENGINE=$engine CHARACTER SET utf8mb4 COLLATE utf8mb4_bin";
+    }
+    
+    function preferredEngine($def)
+    {
+        if (!empty($def['fulltext indexes'])) {
+            return 'MyISAM';
+        }
+        return 'InnoDB';
     }
 
     /**
@@ -272,152 +299,47 @@ class MysqlSchema extends Schema
     }
 
     /**
-     * Ensures that a table exists with the given
-     * name and the given column definitions.
-     *
-     * If the table does not yet exist, it will
-     * create the table. If it does exist, it will
-     * alter the table to match the column definitions.
-     *
-     * @param string $tableName name of the table
-     * @param array  $columns   array of ColumnDef
-     *                          objects for the table
+     * MySQL doesn't take 'DROP CONSTRAINT', need to treat primary keys as
+     * if they were indexes here, but can use 'PRIMARY KEY' special name.
      *
-     * @return boolean success flag
+     * @param array $phrase
      */
-
-    public function oldensureTable($tableName, $columns)
+    function appendAlterDropPrimary(array &$phrase)
     {
-        // XXX: DB engine portability -> toilet
-
-        try {
-            $td = $this->getTableDef($tableName);
-        } catch (SchemaTableMissingException $e) {
-            return $this->createTable($tableName, $columns);
-        }
-
-        $cur = $this->_names($td->columns);
-        $new = $this->_names($columns);
-
-        $dropIndex  = array();
-        $toadd      = array_diff($new, $cur);
-        $todrop     = array_diff($cur, $new);
-        $same       = array_intersect($new, $cur);
-        $tomod      = array();
-        $addIndex   = array();
-        $tableProps = array();
-
-        foreach ($same as $m) {
-            $curCol = $this->_byName($td->columns, $m);
-            $newCol = $this->_byName($columns, $m);
-
-            if (!$newCol->equals($curCol)) {
-                $tomod[] = $newCol->name;
-                continue;
-            }
-
-            // Earlier versions may have accidentally left tables at default
-            // charsets which might be latin1 or other freakish things.
-            if ($this->_isString($curCol)) {
-                if ($curCol->charset != 'utf8') {
-                    $tomod[] = $newCol->name;
-                    continue;
-                }
-            }
-        }
-
-        // Find any indices we have to change...
-        $curIdx = $this->_indexList($td->columns);
-        $newIdx = $this->_indexList($columns);
-
-        if ($curIdx['primary'] != $newIdx['primary']) {
-            if ($curIdx['primary']) {
-                $dropIndex[] = 'drop primary key';
-            }
-            if ($newIdx['primary']) {
-                $keys = implode(',', $newIdx['primary']);
-                $addIndex[] = "add constraint primary key ($keys)";
-            }
-        }
-
-        $dropUnique = array_diff($curIdx['uniques'], $newIdx['uniques']);
-        $addUnique = array_diff($newIdx['uniques'], $curIdx['uniques']);
-        foreach ($dropUnique as $columnName) {
-            $dropIndex[] = 'drop key ' . $this->_uniqueKey($tableName, $columnName);
-        }
-        foreach ($addUnique as $columnName) {
-            $addIndex[] = 'add constraint unique key ' . $this->_uniqueKey($tableName, $columnName) . " ($columnName)";;
-        }
+        $phrase[] = 'DROP PRIMARY KEY';
+    }
 
-        $dropMultiple = array_diff($curIdx['indices'], $newIdx['indices']);
-        $addMultiple = array_diff($newIdx['indices'], $curIdx['indices']);
-        foreach ($dropMultiple as $columnName) {
-            $dropIndex[] = 'drop key ' . $this->_key($tableName, $columnName);
-        }
-        foreach ($addMultiple as $columnName) {
-            $addIndex[] = 'add key ' . $this->_key($tableName, $columnName) . " ($columnName)";
-        }
+    /**
+     * MySQL doesn't take 'DROP CONSTRAINT', need to treat unique keys as
+     * if they were indexes here.
+     *
+     * @param array $phrase
+     * @param <type> $keyName MySQL
+     */
+    function appendAlterDropUnique(array &$phrase, $keyName)
+    {
+        $phrase[] = 'DROP INDEX ' . $keyName;
+    }
 
+    /**
+     * Throw some table metadata onto the ALTER TABLE if we have a mismatch
+     * in expected type, collation.
+     */
+    function appendAlterExtras(array &$phrase, $tableName, array $def)
+    {
         // Check for table properties: make sure we're using a sane
         // engine type and charset/collation.
         // @fixme make the default engine configurable?
         $oldProps = $this->getTableProperties($tableName, array('ENGINE', 'TABLE_COLLATION'));
-        if (strtolower($oldProps['ENGINE']) != 'innodb') {
-            $tableProps['ENGINE'] = 'InnoDB';
-        }
-        if (strtolower($oldProps['TABLE_COLLATION']) != 'utf8_bin') {
-            $tableProps['DEFAULT CHARSET'] = 'utf8';
-            $tableProps['COLLATE'] = 'utf8_bin';
-        }
-
-        if (count($dropIndex) + count($toadd) + count($todrop) + count($tomod) + count($addIndex) + count($tableProps) == 0) {
-            // nothing to do
-            return true;
-        }
-
-        // For efficiency, we want this all in one
-        // query, instead of using our methods.
-
-        $phrase = array();
-
-        foreach ($dropIndex as $indexSql) {
-            $phrase[] = $indexSql;
-        }
-
-        foreach ($toadd as $columnName) {
-            $cd = $this->_byName($columns, $columnName);
-
-            $phrase[] = 'ADD COLUMN ' . $this->_columnSql($cd);
+        $engine = $this->preferredEngine($def);
+        if (strtolower($oldProps['ENGINE']) != strtolower($engine)) {
+            $phrase[] = "ENGINE=$engine";
         }
-
-        foreach ($todrop as $columnName) {
-            $phrase[] = 'DROP COLUMN ' . $columnName;
+        if (strtolower($oldProps['TABLE_COLLATION']) != 'utf8mb4_bin') {
+            $phrase[] = 'CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin';
+            $phrase[] = 'DEFAULT CHARACTER SET = utf8mb4';
+            $phrase[] = 'DEFAULT COLLATE = utf8mb4_bin';
         }
-
-        foreach ($tomod as $columnName) {
-            $cd = $this->_byName($columns, $columnName);
-
-            $phrase[] = 'MODIFY COLUMN ' . $this->_columnSql($cd);
-        }
-
-        foreach ($addIndex as $indexSql) {
-            $phrase[] = $indexSql;
-        }
-
-        foreach ($tableProps as $key => $val) {
-            $phrase[] = "$key=$val";
-        }
-
-        $sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase);
-
-        common_log(LOG_DEBUG, __METHOD__ . ': ' . $sql);
-        $res = $this->conn->query($sql);
-
-        if (PEAR::isError($res)) {
-            throw new Exception($res->getMessage());
-        }
-
-        return true;
     }
 
     /**
@@ -446,7 +368,8 @@ class MysqlSchema extends Schema
         $line = array();
         $line[] = parent::columnSql($cd);
 
-        if ($cd['type'] == 'serial') {
+        // This'll have been added from our transform of 'serial' type
+        if (!empty($cd['auto_increment'])) {
             $line[] = 'auto_increment';
         }
 
@@ -483,42 +406,20 @@ class MysqlSchema extends Schema
         return $type;
     }
 
-    /**
-     * Map a MySQL native type back to an independent type + size
-     *
-     * @param string $type
-     * @return array ($type, $size) -- $size may be null
-     */
-    protected function reverseMapType($type)
-    {
-        $type = strtolower($type);
-        $map = array(
-            'decimal' => array('numeric', null),
-            'tinyint' => array('int', 'tiny'),
-            'smallint' => array('int', 'small'),
-            'mediumint' => array('int', 'medium'),
-            'bigint' => array('int', 'big'),
-            'tinyblob' => array('blob', 'tiny'),
-            'mediumblob' => array('blob', 'medium'),
-            'longblob' => array('blob', 'long'),
-            'tinytext' => array('text', 'tiny'),
-            'mediumtext' => array('text', 'medium'),
-            'longtext' => array('text', 'long'),
-        );
-        if (isset($map[$type])) {
-            return $map[$type];
-        } else {
-            return array($type, null);
-        }
-    }
-
     function typeAndSize($column)
     {
         if ($column['type'] == 'enum') {
             $vals = array_map(array($this, 'quote'), $column['enum']);
             return 'enum(' . implode(',', $vals) . ')';
         } else if ($this->_isString($column)) {
-            return parent::typeAndSize($column) . ' CHARSET utf8';
+            $col = parent::typeAndSize($column);
+            if (!empty($column['charset'])) {
+                $col .= ' CHARSET ' . $column['charset'];
+            }
+            if (!empty($column['collate'])) {
+                $col .= ' COLLATE ' . $column['collate'];
+            }
+            return $col;
         } else {
             return parent::typeAndSize($column);
         }
@@ -535,8 +436,20 @@ class MysqlSchema extends Schema
      */
     function filterDef(array $tableDef)
     {
-        // @fixme add foreign-key support for MySQL
-        unset($tableDef['foreign keys']);
+        foreach ($tableDef['fields'] as $name => &$col) {
+            if ($col['type'] == 'serial') {
+                $col['type'] = 'int';
+                $col['auto_increment'] = true;
+            }
+            if ($col['type'] == 'datetime' && isset($col['default']) && $col['default'] == 'CURRENT_TIMESTAMP') {
+                $col['type'] = 'timestamp';
+            }
+            $col['type'] = $this->mapType($col);
+            unset($col['size']);
+        }
+        if (!common_config('db', 'mysql_foreign_keys')) {
+            unset($tableDef['foreign keys']);
+        }
         return $tableDef;
     }
 }