Browse Source

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
mark_story 12 years ago
parent
commit
97ab2c0e9b

+ 21 - 2
lib/Cake/Model/Datasource/Database/Mysql.php

@@ -85,7 +85,13 @@ class Mysql extends DboSource {
 	public $fieldParameters = array(
 		'charset' => array('value' => 'CHARACTER SET', 'quote' => false, 'join' => ' ', 'column' => false, '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),
 				'null' => ($column->Null === 'YES' ? true : false),
 				'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])) {
 				$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', '>=');
 	}
 
+/**
+ * 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;
+	}
+
 }

+ 5 - 2
lib/Cake/Model/Datasource/DboSource.php

@@ -3232,14 +3232,17 @@ class DboSource extends DataSource {
 	protected function _buildFieldParameters($columnString, $columnData, $position) {
 		foreach ($this->fieldParameters as $paramName => $value) {
 			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;
 				}
 				$val = $columnData[$paramName];
 				if ($value['quote']) {
 					$val = $this->value($val);
 				}
-				$columnString .= ' ' . $value['value'] . $value['join'] . $val;
+				$columnString .= ' ' . $value['value'] . (empty($value['noVal']) ? $value['join'] . $val : '');
 			}
 		}
 		return $columnString;

+ 132 - 1
lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php

@@ -45,7 +45,7 @@ class MysqlTest extends CakeTestCase {
 	public $fixtures = array(
 		'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.binary_test', 'core.inno'
+		'core.binary_test', 'core.inno', 'core.unsigned'
 	);
 
 /**
@@ -3104,6 +3104,137 @@ class MysqlTest extends CakeTestCase {
 	}
 
 /**
+ * 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()
  *
  * @return void

+ 1 - 1
lib/Cake/Test/Case/Model/ModelIntegrationTest.php

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

+ 61 - 0
lib/Cake/Test/Fixture/UnsignedFixture.php

@@ -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();
+}