Browse Source

Merge pull request #8543 from cakephp/mysql-text-type

Add support for tinytext, mediumtext and longtext for MySQL.

Other database platforms will use VARCHAR columns for TINYTEXT
and TEXT for the medium and long variants of TEXT.
Mark Story 10 years ago
parent
commit
01c1502e54

+ 16 - 1
src/Database/Schema/MysqlSchema.php

@@ -116,6 +116,8 @@ class MysqlSchema extends BaseSchema
             return ['type' => 'string', 'length' => $length];
         }
         if (strpos($col, 'text') !== false) {
+            $lengthName = substr($col, 0, -4);
+            $length = isset(Table::$columnLengths[$lengthName]) ? Table::$columnLengths[$lengthName] : null;
             return ['type' => 'text', 'length' => $length];
         }
         if (strpos($col, 'blob') !== false || $col === 'binary') {
@@ -289,7 +291,6 @@ class MysqlSchema extends BaseSchema
             'binary' => ' LONGBLOB',
             'float' => ' FLOAT',
             'decimal' => ' DECIMAL',
-            'text' => ' TEXT',
             'date' => ' DATE',
             'time' => ' TIME',
             'datetime' => ' DATETIME',
@@ -298,6 +299,7 @@ class MysqlSchema extends BaseSchema
         ];
         $specialMap = [
             'string' => true,
+            'text' => true,
         ];
         if (isset($typeMap[$data['type']])) {
             $out .= $typeMap[$data['type']];
@@ -310,6 +312,19 @@ class MysqlSchema extends BaseSchema
                         $data['length'] = 255;
                     }
                     break;
+                case 'text':
+                    $isKnownLength = in_array($data['length'], Table::$columnLengths);
+                    if (empty($data['length']) || !$isKnownLength) {
+                        $out .= ' TEXT';
+                        break;
+                    }
+
+                    if ($isKnownLength) {
+                        $length = array_search($data['length'], Table::$columnLengths);
+                        $out .= ' ' . strtoupper($length) . 'TEXT';
+                    }
+
+                    break;
             }
         }
         $hasLength = ['integer', 'string'];

+ 5 - 2
src/Database/Schema/PostgresSchema.php

@@ -334,7 +334,6 @@ class PostgresSchema extends BaseSchema
             'binary' => ' BYTEA',
             'float' => ' FLOAT',
             'decimal' => ' DECIMAL',
-            'text' => ' TEXT',
             'date' => ' DATE',
             'time' => ' TIME',
             'datetime' => ' TIMESTAMP',
@@ -355,7 +354,11 @@ class PostgresSchema extends BaseSchema
             $out .= $type;
         }
 
-        if ($data['type'] === 'string') {
+        if ($data['type'] === 'text' && $data['length'] !== Table::LENGTH_TINY) {
+            $out .= ' TEXT';
+        }
+
+        if ($data['type'] === 'string' || ($data['type'] === 'text' && $data['length'] === Table::LENGTH_TINY)) {
             $isFixed = !empty($data['fixed']);
             $type = ' VARCHAR';
             if ($isFixed) {

+ 20 - 10
src/Database/Schema/SqliteSchema.php

@@ -245,22 +245,16 @@ class SqliteSchema extends BaseSchema
         $data = $table->column($name);
         $typeMap = [
             'uuid' => ' CHAR(36)',
-            'string' => ' VARCHAR',
-            'integer' => ' INTEGER',
             'biginteger' => ' BIGINT',
             'boolean' => ' BOOLEAN',
             'binary' => ' BLOB',
             'float' => ' FLOAT',
             'decimal' => ' DECIMAL',
-            'text' => ' TEXT',
             'date' => ' DATE',
             'time' => ' TIME',
             'datetime' => ' DATETIME',
             'timestamp' => ' TIMESTAMP',
         ];
-        if (!isset($typeMap[$data['type']])) {
-            throw new Exception(sprintf('Unknown column type for "%s"', $name));
-        }
 
         $out = $this->_driver->quoteIdentifier($name);
         $hasUnsigned = ['biginteger', 'integer', 'float', 'decimal'];
@@ -272,14 +266,30 @@ class SqliteSchema extends BaseSchema
                 $out .= ' UNSIGNED';
             }
         }
-        $out .= $typeMap[$data['type']];
 
-        $hasLength = ['integer', 'string'];
-        if (in_array($data['type'], $hasLength, true) && isset($data['length'])) {
-            if ($data['type'] !== 'integer' || [$name] !== (array)$table->primaryKey()) {
+        if (isset($typeMap[$data['type']])) {
+            $out .= $typeMap[$data['type']];
+        }
+
+        if ($data['type'] === 'text' && $data['length'] !== Table::LENGTH_TINY) {
+            $out .= ' TEXT';
+        }
+
+        if ($data['type'] === 'string' || ($data['type'] === 'text' && $data['length'] === Table::LENGTH_TINY)) {
+            $out .= ' VARCHAR';
+
+            if (isset($data['length'])) {
+                $out .= '(' . (int)$data['length'] . ')';
+            }
+        }
+
+        if ($data['type'] === 'integer') {
+            $out .= ' INTEGER';
+            if (isset($data['length']) && [$name] !== (array)$table->primaryKey()) {
                 $out .= '(' . (int)$data['length'] . ')';
             }
         }
+
         $hasPrecision = ['float', 'decimal'];
         if (in_array($data['type'], $hasPrecision, true) &&
             (isset($data['length']) || isset($data['precision']))

+ 5 - 2
src/Database/Schema/SqlserverSchema.php

@@ -305,7 +305,6 @@ class SqlserverSchema extends BaseSchema
             'binary' => ' VARBINARY(MAX)',
             'float' => ' FLOAT',
             'decimal' => ' DECIMAL',
-            'text' => ' NVARCHAR(MAX)',
             'date' => ' DATE',
             'time' => ' TIME',
             'datetime' => ' DATETIME',
@@ -324,7 +323,11 @@ class SqlserverSchema extends BaseSchema
             }
         }
 
-        if ($data['type'] === 'string') {
+        if ($data['type'] === 'text' && $data['length'] !== Table::LENGTH_TINY) {
+            $out .= ' NVARCHAR(MAX)';
+        }
+
+        if ($data['type'] === 'string' || ($data['type'] === 'text' && $data['length'] === Table::LENGTH_TINY)) {
             $type = ' NVARCHAR';
 
             if (!empty($data['fixed'])) {

+ 32 - 0
src/Database/Schema/Table.php

@@ -82,6 +82,38 @@ class Table
     protected $_temporary = false;
 
     /**
+     * Column length when using a `tiny` column type
+     *
+     * @var int
+     */
+    const LENGTH_TINY = 255;
+
+    /**
+     * Column length when using a `medium` column type
+     *
+     * @var int
+     */
+    const LENGTH_MEDIUM = 16777215;
+
+    /**
+     * Column length when using a `long` column type
+     *
+     * @var int
+     */
+    const LENGTH_LONG = 4294967295;
+
+    /**
+     * Valid column length that can be used with text type columns
+     *
+     * @var array
+     */
+    public static $columnLengths = [
+        'tiny' => self::LENGTH_TINY,
+        'medium' => self::LENGTH_MEDIUM,
+        'long' => self::LENGTH_LONG
+    ];
+
+    /**
      * The valid keys that can be used in a column
      * definition.
      *

+ 5 - 3
tests/Fixture/TagsFixture.php

@@ -14,6 +14,7 @@
  */
 namespace Cake\Test\Fixture;
 
+use Cake\Database\Schema\Table;
 use Cake\TestSuite\Fixture\TestFixture;
 
 /**
@@ -31,6 +32,7 @@ class TagsFixture extends TestFixture
     public $fields = [
         'id' => ['type' => 'integer', 'null' => false],
         'name' => ['type' => 'string', 'null' => false],
+        'description' => ['type' => 'text', 'length' => Table::LENGTH_MEDIUM],
         '_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]]
     ];
 
@@ -40,8 +42,8 @@ class TagsFixture extends TestFixture
      * @var array
      */
     public $records = [
-        ['name' => 'tag1'],
-        ['name' => 'tag2'],
-        ['name' => 'tag3']
+        ['name' => 'tag1', 'description' => 'A big description'],
+        ['name' => 'tag2', 'description' => 'Another big description'],
+        ['name' => 'tag3', 'description' => 'Yet another one']
     ];
 }

+ 25 - 2
tests/TestCase/Database/Schema/MysqlSchemaTest.php

@@ -100,7 +100,15 @@ class MysqlSchemaTest extends TestCase
             ],
             [
                 'TINYTEXT',
-                ['type' => 'text', 'length' => null]
+                ['type' => 'text', 'length' => Table::LENGTH_TINY]
+            ],
+            [
+                'MEDIUMTEXT',
+                ['type' => 'text', 'length' => Table::LENGTH_MEDIUM]
+            ],
+            [
+                'LONGTEXT',
+                ['type' => 'text', 'length' => Table::LENGTH_LONG]
             ],
             [
                 'BLOB',
@@ -150,7 +158,7 @@ class MysqlSchemaTest extends TestCase
     }
 
     /**
-     * Test parsing MySQL column types form field description.
+     * Test parsing MySQL column types from field description.
      *
      * @dataProvider convertColumnProvider
      * @return void
@@ -466,6 +474,21 @@ SQL;
                 ['type' => 'text', 'null' => false],
                 '`body` TEXT NOT NULL'
             ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_TINY, 'null' => false],
+                '`body` TINYTEXT NOT NULL'
+            ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_MEDIUM, 'null' => false],
+                '`body` MEDIUMTEXT NOT NULL'
+            ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_LONG, 'null' => false],
+                '`body` LONGTEXT NOT NULL'
+            ],
             // Integers
             [
                 'post_id',

+ 16 - 0
tests/TestCase/Database/Schema/PostgresSchemaTest.php

@@ -16,6 +16,7 @@ namespace Cake\Test\TestCase\Database\Schema;
 
 use Cake\Core\Configure;
 use Cake\Database\Schema\Collection as SchemaCollection;
+use Cake\Database\Schema\MysqlSchema;
 use Cake\Database\Schema\PostgresSchema;
 use Cake\Database\Schema\Table;
 use Cake\Datasource\ConnectionManager;
@@ -628,6 +629,21 @@ SQL;
                 ['type' => 'text', 'null' => false],
                 '"body" TEXT NOT NULL'
             ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_TINY, 'null' => false],
+                '"body" VARCHAR(' . Table::LENGTH_TINY . ') NOT NULL'
+            ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_MEDIUM, 'null' => false],
+                '"body" TEXT NOT NULL'
+            ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_LONG, 'null' => false],
+                '"body" TEXT NOT NULL'
+            ],
             // Integers
             [
                 'post_id',

+ 15 - 0
tests/TestCase/Database/Schema/SqliteSchemaTest.php

@@ -454,6 +454,21 @@ SQL;
                 ['type' => 'text', 'null' => false],
                 '"body" TEXT NOT NULL'
             ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_TINY, 'null' => false],
+                '"body" VARCHAR(' . Table::LENGTH_TINY . ') NOT NULL'
+            ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_MEDIUM, 'null' => false],
+                '"body" TEXT NOT NULL'
+            ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_LONG, 'null' => false],
+                '"body" TEXT NOT NULL'
+            ],
             // Integers
             [
                 'post_id',

+ 15 - 0
tests/TestCase/Database/Schema/SqlserverSchemaTest.php

@@ -487,6 +487,21 @@ SQL;
                 ['type' => 'text', 'null' => false],
                 '[body] NVARCHAR(MAX) NOT NULL'
             ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_TINY, 'null' => false],
+                '[body] NVARCHAR(' . Table::LENGTH_TINY . ') NOT NULL'
+            ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_MEDIUM, 'null' => false],
+                '[body] NVARCHAR(MAX) NOT NULL'
+            ],
+            [
+                'body',
+                ['type' => 'text', 'length' => Table::LENGTH_LONG, 'null' => false],
+                '[body] NVARCHAR(MAX) NOT NULL'
+            ],
             // Integers
             [
                 'post_id',

+ 24 - 12
tests/TestCase/ORM/QueryTest.php

@@ -569,12 +569,14 @@ class QueryTest extends TestCase
                     [
                         'id' => 1,
                         'name' => 'tag1',
-                        '_joinData' => ['article_id' => 1, 'tag_id' => 1]
+                        '_joinData' => ['article_id' => 1, 'tag_id' => 1],
+                        'description' => 'A big description'
                     ],
                     [
                         'id' => 2,
                         'name' => 'tag2',
-                        '_joinData' => ['article_id' => 1, 'tag_id' => 2]
+                        '_joinData' => ['article_id' => 1, 'tag_id' => 2],
+                        'description' => 'Another big description'
                     ]
                 ]
             ],
@@ -588,12 +590,14 @@ class QueryTest extends TestCase
                     [
                         'id' => 1,
                         'name' => 'tag1',
-                        '_joinData' => ['article_id' => 2, 'tag_id' => 1]
+                        '_joinData' => ['article_id' => 2, 'tag_id' => 1],
+                        'description' => 'A big description'
                     ],
                     [
                         'id' => 3,
                         'name' => 'tag3',
-                        '_joinData' => ['article_id' => 2, 'tag_id' => 3]
+                        '_joinData' => ['article_id' => 2, 'tag_id' => 3],
+                        'description' => 'Yet another one'
                     ]
                 ]
             ],
@@ -631,7 +635,8 @@ class QueryTest extends TestCase
                     [
                         'id' => 3,
                         'name' => 'tag3',
-                        '_joinData' => ['article_id' => 2, 'tag_id' => 3]
+                        '_joinData' => ['article_id' => 2, 'tag_id' => 3],
+                        'description' => 'Yet another one'
                     ]
                 ]
             ],
@@ -745,6 +750,7 @@ class QueryTest extends TestCase
                     'Tags' => [
                         'id' => 3,
                         'name' => 'tag3',
+                        'description' => 'Yet another one',
                     ],
                     'ArticlesTags' => ['article_id' => 2, 'tag_id' => 3]
                 ]
@@ -770,6 +776,7 @@ class QueryTest extends TestCase
                     'Tags' => [
                         'id' => 2,
                         'name' => 'tag2',
+                        'description' => 'Another big description',
                     ],
                     'ArticlesTags' => ['article_id' => 1, 'tag_id' => 2]
                 ]
@@ -806,6 +813,7 @@ class QueryTest extends TestCase
                     'tags' => [
                         'id' => 2,
                         'name' => 'tag2',
+                        'description' => 'Another big description',
                     ],
                     'articles' => [
                         'id' => 1,
@@ -815,9 +823,9 @@ class QueryTest extends TestCase
                         'published' => 'Y'
                     ],
                     'ArticlesTags' => [
-                            'article_id' => 1,
-                            'tag_id' => 2
-                        ]
+                        'article_id' => 1,
+                        'tag_id' => 2
+                    ]
                 ]
             ]
         ];
@@ -1259,14 +1267,16 @@ class QueryTest extends TestCase
         $expected = [
             'id' => 1,
             'name' => 'tag1',
-            '_joinData' => ['article_id' => 1, 'tag_id' => 1]
+            '_joinData' => ['article_id' => 1, 'tag_id' => 1],
+            'description' => 'A big description',
         ];
         $this->assertEquals($expected, $first->tags[0]->toArray());
 
         $expected = [
             'id' => 2,
             'name' => 'tag2',
-            '_joinData' => ['article_id' => 1, 'tag_id' => 2]
+            '_joinData' => ['article_id' => 1, 'tag_id' => 2],
+            'description' => 'Another big description'
         ];
         $this->assertEquals($expected, $first->tags[1]->toArray());
     }
@@ -1310,14 +1320,16 @@ class QueryTest extends TestCase
         $expected = [
             'id' => 1,
             'name' => 'tag1',
-            '_joinData' => ['article_id' => 1, 'tag_id' => 1]
+            '_joinData' => ['article_id' => 1, 'tag_id' => 1],
+            'description' => 'A big description',
         ];
         $this->assertEquals($expected, $first->tags[0]->toArray());
 
         $expected = [
             'id' => 2,
             'name' => 'tag2',
-            '_joinData' => ['article_id' => 1, 'tag_id' => 2]
+            '_joinData' => ['article_id' => 1, 'tag_id' => 2],
+            'description' => 'Another big description'
         ];
         $this->assertEquals($expected, $first->tags[1]->toArray());
     }

+ 2 - 1
tests/TestCase/ORM/TableTest.php

@@ -3869,7 +3869,8 @@ class TableTest extends TestCase
         ], $options);
 
         $newTag = new \TestApp\Model\Entity\Tag([
-            'name' => 'Foo'
+            'name' => 'Foo',
+            'description' => 'Foo desc'
         ], $source);
         $tags[] = new \TestApp\Model\Entity\Tag([
             'id' => 3