Merge branch 'imsamurai-2.5' into 2.5

Add unsigned integer support to MySQL. Unsigned integers have not been
added to other databases as they either do not support them (postgres,
sqlserver) or they are 'faked' and don't do anything (sqlite).

Fixes #2321
This commit is contained in:
mark_story 2013-11-27 20:11:35 -05:00
commit 97ab2c0e9b
5 changed files with 220 additions and 6 deletions

View file

@ -85,7 +85,13 @@ class Mysql extends DboSource {
public $fieldParameters = array( public $fieldParameters = array(
'charset' => array('value' => 'CHARACTER SET', 'quote' => false, 'join' => ' ', 'column' => false, 'position' => 'beforeDefault'), 'charset' => array('value' => 'CHARACTER SET', 'quote' => false, 'join' => ' ', 'column' => false, 'position' => 'beforeDefault'),
'collate' => array('value' => 'COLLATE', 'quote' => false, 'join' => ' ', 'column' => 'Collation', 'position' => 'beforeDefault'), 'collate' => array('value' => 'COLLATE', 'quote' => false, 'join' => ' ', 'column' => 'Collation', 'position' => 'beforeDefault'),
'comment' => array('value' => 'COMMENT', 'quote' => true, 'join' => ' ', 'column' => 'Comment', 'position' => 'afterDefault') 'comment' => array('value' => 'COMMENT', 'quote' => true, 'join' => ' ', 'column' => 'Comment', 'position' => 'afterDefault'),
'unsigned' => array(
'value' => 'UNSIGNED', 'quote' => false, 'join' => ' ', 'column' => false, 'position' => 'beforeDefault',
'noVal' => true,
'options' => array(true),
'types' => array('integer', 'float', 'decimal', 'biginteger')
)
); );
/** /**
@ -340,8 +346,11 @@ class Mysql extends DboSource {
'type' => $this->column($column->Type), 'type' => $this->column($column->Type),
'null' => ($column->Null === 'YES' ? true : false), 'null' => ($column->Null === 'YES' ? true : false),
'default' => $column->Default, 'default' => $column->Default,
'length' => $this->length($column->Type), 'length' => $this->length($column->Type)
); );
if (in_array($fields[$column->Field]['type'], $this->fieldParameters['unsigned']['types'], true)) {
$fields[$column->Field]['unsigned'] = $this->_unsigned($column->Type);
}
if (!empty($column->Key) && isset($this->index[$column->Key])) { if (!empty($column->Key) && isset($this->index[$column->Key])) {
$fields[$column->Field]['key'] = $this->index[$column->Key]; $fields[$column->Field]['key'] = $this->index[$column->Key];
} }
@ -793,4 +802,14 @@ class Mysql extends DboSource {
return $this->useNestedTransactions && version_compare($this->getVersion(), '4.1', '>='); return $this->useNestedTransactions && version_compare($this->getVersion(), '4.1', '>=');
} }
/**
* Check if column type is unsigned
*
* @param string $real Real database-layer column type (i.e. "varchar(255)")
* @return bool True if column is unsigned, false otherwise
*/
protected function _unsigned($real) {
return strpos(strtolower($real), 'unsigned') !== false;
}
} }

View file

@ -3232,14 +3232,17 @@ class DboSource extends DataSource {
protected function _buildFieldParameters($columnString, $columnData, $position) { protected function _buildFieldParameters($columnString, $columnData, $position) {
foreach ($this->fieldParameters as $paramName => $value) { foreach ($this->fieldParameters as $paramName => $value) {
if (isset($columnData[$paramName]) && $value['position'] == $position) { if (isset($columnData[$paramName]) && $value['position'] == $position) {
if (isset($value['options']) && !in_array($columnData[$paramName], $value['options'])) { if (isset($value['options']) && !in_array($columnData[$paramName], $value['options'], true)) {
continue;
}
if (isset($value['types']) && !in_array($columnData['type'], $value['types'], true)) {
continue; continue;
} }
$val = $columnData[$paramName]; $val = $columnData[$paramName];
if ($value['quote']) { if ($value['quote']) {
$val = $this->value($val); $val = $this->value($val);
} }
$columnString .= ' ' . $value['value'] . $value['join'] . $val; $columnString .= ' ' . $value['value'] . (empty($value['noVal']) ? $value['join'] . $val : '');
} }
} }
return $columnString; return $columnString;

View file

@ -45,7 +45,7 @@ class MysqlTest extends CakeTestCase {
public $fixtures = array( public $fixtures = array(
'core.apple', 'core.article', 'core.articles_tag', 'core.attachment', 'core.comment', 'core.apple', 'core.article', 'core.articles_tag', 'core.attachment', 'core.comment',
'core.sample', 'core.tag', 'core.user', 'core.post', 'core.author', 'core.data_test', 'core.sample', 'core.tag', 'core.user', 'core.post', 'core.author', 'core.data_test',
'core.binary_test', 'core.inno' 'core.binary_test', 'core.inno', 'core.unsigned'
); );
/** /**
@ -3103,6 +3103,137 @@ class MysqlTest extends CakeTestCase {
$this->Dbo->buildColumn($data); $this->Dbo->buildColumn($data);
} }
/**
* Test `unsigned` field parameter
*
* @param array $data Column data
* @param string $expected Expected sql part
*
* @return void
*
* @dataProvider buildColumnUnsignedProvider
*/
public function testBuildColumnUnsigned($data, $expected) {
$result = $this->Dbo->buildColumn($data);
$this->assertEquals($expected, $result);
}
/**
* Data provider testBuildColumnUnsigned method
*
* @return array
*/
public function buildColumnUnsignedProvider() {
return array(
//set #0
array(
array(
'name' => 'testName',
'type' => 'integer',
'length' => 11,
'unsigned' => true
),
'`testName` int(11) UNSIGNED'
),
//set #1
array(
array(
'name' => 'testName',
'type' => 'biginteger',
'length' => 20,
'unsigned' => true
),
'`testName` bigint(20) UNSIGNED'
),
//set #2
array(
array(
'name' => 'testName',
'type' => 'float',
'unsigned' => true
),
'`testName` float UNSIGNED'
),
//set #3
array(
array(
'name' => 'testName',
'type' => 'string',
'length' => 255,
'unsigned' => true
),
'`testName` varchar(255)'
),
//set #4
array(
array(
'name' => 'testName',
'type' => 'date',
'unsigned' => true
),
'`testName` date'
),
//set #5
array(
array(
'name' => 'testName',
'type' => 'date',
'unsigned' => false
),
'`testName` date'
),
//set #6
array(
array(
'name' => 'testName',
'type' => 'integer',
'length' => 11,
'unsigned' => false
),
'`testName` int(11)'
),
//set #7
array(
array(
'name' => 'testName',
'type' => 'decimal',
'unsigned' => true
),
'`testName` decimal UNSIGNED'
),
//set #8
array(
array(
'name' => 'testName',
'type' => 'decimal',
'unsigned' => true,
'default' => 1
),
'`testName` decimal UNSIGNED DEFAULT 1'
)
);
}
/**
* Test getting `unsigned` field parameter from DB
*
* @return void
*/
public function testSchemaUnsigned() {
$this->loadFixtures('Unsigned');
$Model = ClassRegistry::init('Model');
$Model->setSource('unsigned');
$types = $this->Dbo->fieldParameters['unsigned']['types'];
$schema = $Model->schema();
foreach ($types as $type) {
$this->assertArrayHasKey('unsigned', $schema['u' . $type]);
$this->assertTrue($schema['u' . $type]['unsigned']);
$this->assertArrayHasKey('unsigned', $schema[$type]);
$this->assertFalse($schema[$type]['unsigned']);
}
$this->assertArrayNotHasKey('unsigned', $schema['string']);
}
/** /**
* test hasAny() * test hasAny()
* *

View file

@ -2202,7 +2202,7 @@ class ModelIntegrationTest extends BaseModelTest {
} else { } else {
$intLength = 11; $intLength = 11;
} }
foreach (array('collate', 'charset', 'comment') as $type) { foreach (array('collate', 'charset', 'comment', 'unsigned') as $type) {
foreach ($result as $i => $r) { foreach ($result as $i => $r) {
unset($result[$i][$type]); unset($result[$i][$type]);
} }

View file

@ -0,0 +1,61 @@
<?php
/**
* Short description for file.
*
* PHP 5
*
* CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
* @package Cake.Test.Fixture
* @since CakePHP(tm) v 2.5.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* Short description for class.
*
* @package Cake.Test.Fixture
*/
class UnsignedFixture extends CakeTestFixture {
/**
* table property
*
* @var array
*/
public $table = 'unsigned';
/**
* fields property
*
* @var array
*/
public $fields = array(
'uinteger' => array('type' => 'integer', 'null' => '', 'default' => '1', 'length' => '8', 'key' => 'primary', 'unsigned' => true),
'integer' => array('type' => 'integer', 'length' => '8', 'unsigned' => false),
'udecimal' => array('type' => 'decimal', 'length' => '4', 'unsigned' => true),
'decimal' => array('type' => 'decimal', 'length' => '4'),
'biginteger' => array('type' => 'biginteger', 'length' => '20', 'default' => 3),
'ubiginteger' => array('type' => 'biginteger', 'length' => '20', 'default' => 3, 'unsigned' => true),
'float' => array('type' => 'float', 'length' => '4'),
'ufloat' => array('type' => 'float', 'length' => '4', 'unsigned' => true),
'string' => array('type' => 'string', 'length' => '4'),
'tableParameters' => array(
'engine' => 'MyISAM'
)
);
/**
* records property
*
* @var array
*/
public $records = array();
}