diff --git a/lib/Cake/Model/CakeSchema.php b/lib/Cake/Model/CakeSchema.php index 2fda5f75e..58302e781 100644 --- a/lib/Cake/Model/CakeSchema.php +++ b/lib/Cake/Model/CakeSchema.php @@ -574,13 +574,17 @@ class CakeSchema extends Object { if (is_array($values)) { foreach ($values as $key => $val) { if (is_array($val)) { - $vals[] = "'{$key}' => array('" . implode("', '", $val) . "')"; - } elseif (!is_numeric($key)) { + $vals[] = "'{$key}' => array(" . implode(", ", $this->_values($val)) . ")"; + } else { $val = var_export($val, true); if ($val === 'NULL') { $val = 'null'; } - $vals[] = "'{$key}' => {$val}"; + if (!is_numeric($key)) { + $vals[] = "'{$key}' => {$val}"; + } else { + $vals[] = "{$val}"; + } } } } diff --git a/lib/Cake/Model/Datasource/Database/Mysql.php b/lib/Cake/Model/Datasource/Database/Mysql.php index f96dfa420..d002c50df 100644 --- a/lib/Cake/Model/Datasource/Database/Mysql.php +++ b/lib/Cake/Model/Datasource/Database/Mysql.php @@ -443,6 +443,12 @@ class Mysql extends DboSource { $col[] = $idx->Column_name; $index[$idx->Key_name]['column'] = $col; } + if (!empty($idx->Sub_part)) { + if (!isset($index[$idx->Key_name]['length'])) { + $index[$idx->Key_name]['length'] = array(); + } + $index[$idx->Key_name]['length'][$idx->Column_name] = $idx->Sub_part; + } } // @codingStandardsIgnoreEnd $indices->closeCursor(); @@ -543,6 +549,55 @@ class Mysql extends DboSource { return array(); } +/** + * Format indexes for create table + * + * @param array $indexes An array of indexes to generate SQL from + * @param string $table Optional table name, not used + * @return array An array of SQL statements for indexes + * @see DboSource::buildIndex() + */ + public function buildIndex($indexes, $table = null) { + $join = array(); + foreach ($indexes as $name => $value) { + $out = ''; + if ($name === 'PRIMARY') { + $out .= 'PRIMARY '; + $name = null; + } else { + if (!empty($value['unique'])) { + $out .= 'UNIQUE '; + } + $name = $this->startQuote . $name . $this->endQuote; + } + // length attribute only used for MySQL datasource, for TEXT/BLOB index columns + $out .= 'KEY ' . $name . ' ('; + if (is_array($value['column'])) { + if (isset($value['length'])) { + $vals = array(); + foreach ($value['column'] as $column) { + $name = $this->name($column); + if (isset($value['length'])) { + $name .= $this->_buildIndexSubPart($value['length'], $column); + } + $vals[] = $name; + } + $out .= implode(', ', $vals); + } else { + $out .= implode(', ', array_map(array(&$this, 'name'), $value['column'])); + } + } else { + $out .= $this->name($value['column']); + if (isset($value['length'])) { + $out .= $this->_buildIndexSubPart($value['length'], $value['column']); + } + } + $out .= ')'; + $join[] = $out; + } + return $join; + } + /** * Generate MySQL index alteration statements for a table. * @@ -558,33 +613,37 @@ class Mysql extends DboSource { 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; } +/** + * Format length for text indexes + * + * @param array $lengths An array of lengths for a single index + * @param string $column The column for which to generate the index length + * @return string Formatted length part of an index field + */ + protected function _buildIndexSubPart($lengths, $column) { + if (is_null($lengths)) { + return ''; + } + if (!isset($lengths[$column])) { + return ''; + } + return '(' . $lengths[$column] . ')'; + } + /** * Returns an detailed array of sources (tables) in the database. * diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index 0923bf166..9cb615a67 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -830,7 +830,7 @@ class DboSource extends DataSource { } if (preg_match('/^([\w-]+)\((.*)\)$/', $data, $matches)) { // Functions return $this->cacheMethod(__FUNCTION__, $cacheKey, - $matches[1] . '(' . $this->name($matches[2]) . ')' + $matches[1] . '(' . $this->name($matches[2]) . ')' ); } if ( diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php index 7ae749268..0a3739c3c 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php @@ -313,6 +313,26 @@ 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_text_index'); + $this->Dbo->rawQuery('CREATE TABLE ' . $name . ' (id int(11) AUTO_INCREMENT, text_field text, primary key(id), KEY `text_index` ( `text_field`(20) ));'); + $expected = array( + 'PRIMARY' => array('column' => 'id', 'unique' => 1), + 'text_index' => array('column' => 'text_field', 'unique' => 0, 'length' => array('text_field' => 20)), + ); + $result = $this->Dbo->index('with_text_index', false); + $this->Dbo->rawQuery('DROP TABLE ' . $name); + $this->assertEquals($expected, $result); + + $name = $this->Dbo->fullTableName('with_compound_text_index'); + $this->Dbo->rawQuery('CREATE TABLE ' . $name . ' (id int(11) AUTO_INCREMENT, text_field1 text, text_field2 text, primary key(id), KEY `text_index` ( `text_field1`(20), `text_field2`(20) ));'); + $expected = array( + 'PRIMARY' => array('column' => 'id', 'unique' => 1), + 'text_index' => array('column' => array('text_field1', 'text_field2'), 'unique' => 0, 'length' => array('text_field1' => 20, 'text_field2' => 20)), + ); + $result = $this->Dbo->index('with_compound_text_index', false); + $this->Dbo->rawQuery('DROP TABLE ' . $name); + $this->assertEquals($expected, $result); } /** @@ -548,9 +568,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 @@ -576,13 +596,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); @@ -594,10 +614,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); @@ -2902,6 +2922,20 @@ class MysqlTest extends CakeTestCase { $result = $this->Dbo->buildIndex($data); $expected = array('UNIQUE KEY `MyIndex` (`id`, `name`)'); $this->assertEquals($expected, $result); + + $data = array( + 'MyTextIndex' => array('column' => 'text_field', 'length' => array('text_field' => 20)) + ); + $result = $this->Dbo->buildIndex($data); + $expected = array('KEY `MyTextIndex` (`text_field`(20))'); + $this->assertEquals($expected, $result); + + $data = array( + 'MyMultiTextIndex' => array('column' => array('text_field1', 'text_field2'), 'length' => array('text_field1' => 20, 'text_field2' => 20)) + ); + $result = $this->Dbo->buildIndex($data); + $expected = array('KEY `MyMultiTextIndex` (`text_field1`(20), `text_field2`(20))'); + $this->assertEquals($expected, $result); } /** @@ -2972,7 +3006,7 @@ class MysqlTest extends CakeTestCase { 'type' => 'timestamp', 'default' => 'current_timestamp', 'null' => false, - ); + ); $result = $this->Dbo->buildColumn($data); $expected = '`created` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL'; $this->assertEquals($expected, $result);