From aaefbf1c2f927b0a7f7a2a1c487c2cffa6bc795f Mon Sep 17 00:00:00 2001 From: Ber Clausen Date: Thu, 20 Sep 2012 00:21:26 -0300 Subject: [PATCH] Add MySQL FULLTEXT support. Minor optimizations and testing added. Merge pull request #862 from bar/mysql-fulltext Fixes #262 --- lib/Cake/Model/Datasource/Database/Mysql.php | 35 ++++++--------- lib/Cake/Model/Datasource/DboSource.php | 4 +- lib/Cake/Test/Case/Model/CakeSchemaTest.php | 17 +++++++ .../Model/Datasource/Database/MysqlTest.php | 45 +++++++++++++------ 4 files changed, 64 insertions(+), 37 deletions(-) diff --git a/lib/Cake/Model/Datasource/Database/Mysql.php b/lib/Cake/Model/Datasource/Database/Mysql.php index f75c5330b..bdbaaa6c9 100644 --- a/lib/Cake/Model/Datasource/Database/Mysql.php +++ b/lib/Cake/Model/Datasource/Database/Mysql.php @@ -423,17 +423,21 @@ class Mysql extends DboSource { $table = $this->fullTableName($model); $old = version_compare($this->getVersion(), '4.1', '<='); if ($table) { - $indices = $this->_execute('SHOW INDEX FROM ' . $table); + $indexes = $this->_execute('SHOW INDEX FROM ' . $table); // @codingStandardsIgnoreStart // MySQL columns don't match the cakephp conventions. - while ($idx = $indices->fetch(PDO::FETCH_OBJ)) { + while ($idx = $indexes->fetch(PDO::FETCH_OBJ)) { if ($old) { $idx = (object)current((array)$idx); } if (!isset($index[$idx->Key_name]['column'])) { $col = array(); $index[$idx->Key_name]['column'] = $idx->Column_name; - $index[$idx->Key_name]['unique'] = intval($idx->Non_unique == 0); + if ($idx->Index_type === 'FULLTEXT') { + $index[$idx->Key_name]['type'] = strtolower($idx->Index_type); + } else { + $index[$idx->Key_name]['unique'] = intval($idx->Non_unique == 0); + } } else { if (!empty($index[$idx->Key_name]['column']) && !is_array($index[$idx->Key_name]['column'])) { $col[] = $index[$idx->Key_name]['column']; @@ -443,7 +447,7 @@ class Mysql extends DboSource { } } // @codingStandardsIgnoreEnd - $indices->closeCursor(); + $indexes->closeCursor(); } return $index; } @@ -553,31 +557,18 @@ class Mysql extends DboSource { if (isset($indexes['drop'])) { foreach ($indexes['drop'] as $name => $value) { $out = 'DROP '; - if ($name == 'PRIMARY') { + if ($name === 'PRIMARY') { $out .= 'PRIMARY KEY'; } else { - $out .= 'KEY ' . $name; + $out .= 'KEY ' . $this->startQuote . $name . $this->endQuote; } $alter[] = $out; } } if (isset($indexes['add'])) { - foreach ($indexes['add'] as $name => $value) { - $out = 'ADD '; - if ($name == 'PRIMARY') { - $out .= 'PRIMARY '; - $name = null; - } else { - if (!empty($value['unique'])) { - $out .= 'UNIQUE '; - } - } - if (is_array($value['column'])) { - $out .= 'KEY ' . $name . ' (' . implode(', ', array_map(array(&$this, 'name'), $value['column'])) . ')'; - } else { - $out .= 'KEY ' . $name . ' (' . $this->name($value['column']) . ')'; - } - $alter[] = $out; + $add = $this->buildIndex($indexes['add']); + foreach ($add as $index) { + $alter[] = 'ADD ' . $index; } } return $alter; diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index 387c5e82f..34f1ff75b 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -3125,7 +3125,7 @@ class DboSource extends DataSource { } /** - * Format indexes for create table + * Format indexes for create table. * * @param array $indexes * @param string $table @@ -3141,6 +3141,8 @@ class DboSource extends DataSource { } else { if (!empty($value['unique'])) { $out .= 'UNIQUE '; + } elseif (!empty($value['type']) && strtoupper($value['type']) === 'FULLTEXT') { + $out .= 'FULLTEXT '; } $name = $this->startQuote . $name . $this->endQuote; } diff --git a/lib/Cake/Test/Case/Model/CakeSchemaTest.php b/lib/Cake/Test/Case/Model/CakeSchemaTest.php index 34c782e58..7863af19a 100644 --- a/lib/Cake/Test/Case/Model/CakeSchemaTest.php +++ b/lib/Cake/Test/Case/Model/CakeSchemaTest.php @@ -763,6 +763,23 @@ class CakeSchemaTest extends CakeTestCase { ); $result = $this->Schema->generateTable('posts', $posts); $this->assertRegExp('/public \$posts/', $result); + + $posts = array( + 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'), + 'author_id' => array('type' => 'integer', 'null' => false), + 'title' => array('type' => 'string', 'null' => false), + 'body' => array('type' => 'text', 'null' => true, 'default' => null), + 'published' => array('type' => 'string', 'null' => true, 'default' => 'N', 'length' => 1), + 'created' => array('type' => 'datetime', 'null' => true, 'default' => null), + 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null), + 'indexes' => array( + 'PRIMARY' => array('column' => 'id', 'unique' => true), + 'MyFtIndex' => array('column' => array('title', 'body'), 'type' => 'fulltext') + ) + ); + $result = $this->Schema->generateTable('fields', $posts); + $this->assertRegExp('/public \$fields/', $result); + $this->assertPattern('/\'type\' \=\> \'fulltext\'/', $result); } /** diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php index 4a633b417..caddc5b7a 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php @@ -320,6 +320,16 @@ class MysqlTest extends CakeTestCase { $result = $this->Dbo->index('with_multiple_compound_keys', false); $this->Dbo->rawQuery('DROP TABLE ' . $name); $this->assertEquals($expected, $result); + + $name = $this->Dbo->fullTableName('with_fulltext'); + $this->Dbo->rawQuery('CREATE TABLE ' . $name . ' (id int(11) AUTO_INCREMENT, name varchar(255), description text, primary key(id), FULLTEXT KEY `MyFtIndex` ( `name`, `description` )) ENGINE=MyISAM;'); + $expected = array( + 'PRIMARY' => array('column' => 'id', 'unique' => 1), + 'MyFtIndex' => array('column' => array('name', 'description'), 'type' => 'fulltext') + ); + $result = $this->Dbo->index('with_fulltext', false); + $this->Dbo->rawQuery('DROP TABLE ' . $name); + $this->assertEquals($expected, $result); } /** @@ -559,9 +569,9 @@ class MysqlTest extends CakeTestCase { $result = $this->Dbo->alterSchema($schemaB->compare($schemaA)); $this->assertContains("ALTER TABLE $table", $result); - $this->assertContains('ADD KEY name_idx (`name`),', $result); - $this->assertContains('ADD KEY group_idx (`group1`),', $result); - $this->assertContains('ADD KEY compound_idx (`group1`, `group2`),', $result); + $this->assertContains('ADD KEY `name_idx` (`name`),', $result); + $this->assertContains('ADD KEY `group_idx` (`group1`),', $result); + $this->assertContains('ADD KEY `compound_idx` (`group1`, `group2`),', $result); $this->assertContains('ADD PRIMARY KEY (`id`);', $result); //Test that the string is syntactically correct @@ -587,13 +597,13 @@ class MysqlTest extends CakeTestCase { $result = $this->Dbo->alterSchema($schemaC->compare($schemaB)); $this->assertContains("ALTER TABLE $table", $result); $this->assertContains('DROP PRIMARY KEY,', $result); - $this->assertContains('DROP KEY name_idx,', $result); - $this->assertContains('DROP KEY group_idx,', $result); - $this->assertContains('DROP KEY compound_idx,', $result); - $this->assertContains('ADD KEY id_name_idx (`id`, `name`),', $result); - $this->assertContains('ADD UNIQUE KEY name_idx (`name`),', $result); - $this->assertContains('ADD KEY group_idx (`group2`),', $result); - $this->assertContains('ADD KEY compound_idx (`group2`, `group1`);', $result); + $this->assertContains('DROP KEY `name_idx`,', $result); + $this->assertContains('DROP KEY `group_idx`,', $result); + $this->assertContains('DROP KEY `compound_idx`,', $result); + $this->assertContains('ADD KEY `id_name_idx` (`id`, `name`),', $result); + $this->assertContains('ADD UNIQUE KEY `name_idx` (`name`),', $result); + $this->assertContains('ADD KEY `group_idx` (`group2`),', $result); + $this->assertContains('ADD KEY `compound_idx` (`group2`, `group1`);', $result); $query = $this->Dbo->getConnection()->prepare($result); $this->assertEquals($query->queryString, $result); @@ -605,10 +615,10 @@ class MysqlTest extends CakeTestCase { $result = $this->Dbo->alterSchema($schemaA->compare($schemaC)); $this->assertContains("ALTER TABLE $table", $result); - $this->assertContains('DROP KEY name_idx,', $result); - $this->assertContains('DROP KEY group_idx,', $result); - $this->assertContains('DROP KEY compound_idx,', $result); - $this->assertContains('DROP KEY id_name_idx;', $result); + $this->assertContains('DROP KEY `name_idx`,', $result); + $this->assertContains('DROP KEY `group_idx`,', $result); + $this->assertContains('DROP KEY `compound_idx`,', $result); + $this->assertContains('DROP KEY `id_name_idx`;', $result); $query = $this->Dbo->getConnection()->prepare($result); $this->assertEquals($query->queryString, $result); @@ -2867,6 +2877,13 @@ class MysqlTest extends CakeTestCase { $result = $this->Dbo->buildIndex($data); $expected = array('UNIQUE KEY `MyIndex` (`id`, `name`)'); $this->assertEquals($expected, $result); + + $data = array( + 'MyFtIndex' => array('column' => array('name', 'description'), 'type' => 'fulltext') + ); + $result = $this->Dbo->buildIndex($data); + $expected = array('FULLTEXT KEY `MyFtIndex` (`name`, `description`)'); + $this->assertEquals($expected, $result); } /**