Skip to content

Commit

Permalink
Cater for length part of TEXT field in indexes for MySQL
Browse files Browse the repository at this point in the history
Cater for length on TEXT column in index for _alterIndexes

Handle nested arrays in schemas

Used when writing indexes containg TEXT field for MySQL

Change comment style from code review

Remove stray space

Only generate length part of TEXT index column field when necessary

Override buildIndex() in Mysql instead of name()
Revert DboSource::buildIndex to previous state
Update Mysql::_alterIndexes for code reuse
Update MysqlTest to handle quoted index names.

Make code clearer, as per code review

Adjust function comments, as per code review
  • Loading branch information
rhelms committed Dec 12, 2012
1 parent 0b508b8 commit 07dbc4a
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 36 deletions.
10 changes: 7 additions & 3 deletions lib/Cake/Model/CakeSchema.php
Expand Up @@ -574,13 +574,17 @@ protected function _values($values) {
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}";
}
}
}
}
Expand Down
93 changes: 76 additions & 17 deletions lib/Cake/Model/Datasource/Database/Mysql.php
Expand Up @@ -443,6 +443,12 @@ public function index($model) {
$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();
Expand Down Expand Up @@ -543,6 +549,55 @@ protected function _alterTableParameters($table, $parameters) {
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.
*
Expand All @@ -558,33 +613,37 @@ protected function _alterIndexes($table, $indexes) {
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.
*
Expand Down
2 changes: 1 addition & 1 deletion lib/Cake/Model/Datasource/DboSource.php
Expand Up @@ -830,7 +830,7 @@ public function name($data) {
}
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 (
Expand Down
64 changes: 49 additions & 15 deletions lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php
Expand Up @@ -313,6 +313,26 @@ public function testIndexDetection() {
$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);
}

/**
Expand Down Expand Up @@ -548,9 +568,9 @@ public function testAlterSchemaIndexes() {

$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
Expand All @@ -576,13 +596,13 @@ public function testAlterSchemaIndexes() {
$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);
Expand All @@ -594,10 +614,10 @@ public function testAlterSchemaIndexes() {
$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);
Expand Down Expand Up @@ -2902,6 +2922,20 @@ public function testBuildIndex() {
$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);
}

/**
Expand Down Expand Up @@ -2972,7 +3006,7 @@ public function testBuildColumn2() {
'type' => 'timestamp',
'default' => 'current_timestamp',
'null' => false,
);
);
$result = $this->Dbo->buildColumn($data);
$expected = '`created` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL';
$this->assertEquals($expected, $result);
Expand Down

0 comments on commit 07dbc4a

Please sign in to comment.