From 22b0275a58cadc7548f5904cf588e44b073eb0cd Mon Sep 17 00:00:00 2001 From: Istvan Pusztai Date: Mon, 5 Jan 2015 12:04:24 -0500 Subject: [PATCH] Prevent NULL value on NOT NULL column when value is an empty string (MySQL) --- .../Model/Datasource/Database/Sqlserver.php | 7 +++-- lib/Cake/Model/Datasource/DboSource.php | 13 +++++---- .../Datasource/Database/PostgresTest.php | 4 +-- .../Case/Model/Datasource/DboSourceTest.php | 29 +++++++++++++++++++ 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/lib/Cake/Model/Datasource/Database/Sqlserver.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php index eb7dad8c0..c9cfdf2de 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlserver.php +++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php @@ -584,11 +584,12 @@ class Sqlserver extends DboSource { * * @param string $data String to be prepared for use in an SQL statement * @param string $column The column into which this data will be inserted + * @param bool $null Column allows NULL values * @return string Quoted and escaped data */ - public function value($data, $column = null) { + public function value($data, $column = null, $null = true) { if ($data === null || is_array($data) || is_object($data)) { - return parent::value($data, $column); + return parent::value($data, $column, $null); } if (in_array($data, array('{$__cakeID__$}', '{$__cakeForeignKey__$}'), true)) { return $data; @@ -603,7 +604,7 @@ class Sqlserver extends DboSource { case 'text': return 'N' . $this->_connection->quote($data, PDO::PARAM_STR); default: - return parent::value($data, $column); + return parent::value($data, $column, $null); } } diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index c18f3318a..67277d3ff 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -312,9 +312,10 @@ class DboSource extends DataSource { * * @param string $data String to be prepared for use in an SQL statement * @param string $column The column datatype into which this data will be inserted. + * @param bool $null Column allows NULL values * @return string Quoted and escaped data */ - public function value($data, $column = null) { + public function value($data, $column = null, $null = true) { if (is_array($data) && !empty($data)) { return array_map( array(&$this, 'value'), @@ -348,7 +349,7 @@ class DboSource extends DataSource { return $this->_connection->quote($data, PDO::PARAM_STR); default: if ($data === '') { - return 'NULL'; + return $null ? 'NULL' : '""'; } if (is_float($data)) { return str_replace(',', '.', strval($data)); @@ -994,7 +995,8 @@ class DboSource extends DataSource { $count = count($fields); for ($i = 0; $i < $count; $i++) { - $valueInsert[] = $this->value($values[$i], $Model->getColumnType($fields[$i])); + $schema = $Model->schema(); + $valueInsert[] = $this->value($values[$i], $Model->getColumnType($fields[$i]), isset($schema[$fields[$i]]) ? $schema[$fields[$i]]['null'] : true); $fieldInsert[] = $this->name($fields[$i]); if ($fields[$i] === $Model->primaryKey) { $id = $values[$i]; @@ -2061,6 +2063,7 @@ class DboSource extends DataSource { */ protected function _prepareUpdateFields(Model $Model, $fields, $quoteValues = true, $alias = false) { $quotedAlias = $this->startQuote . $Model->alias . $this->endQuote; + $schema = $Model->schema(); $updates = array(); foreach ($fields as $field => $value) { @@ -2081,7 +2084,7 @@ class DboSource extends DataSource { $update = $quoted . ' = '; if ($quoteValues) { - $update .= $this->value($value, $Model->getColumnType($field)); + $update .= $this->value($value, $Model->getColumnType($field), isset($schema[$field]) ? $schema[$field]['null'] : true); } elseif ($Model->getColumnType($field) === 'boolean' && (is_int($value) || is_bool($value))) { $update .= $this->boolean($value, true); } elseif (!$alias) { @@ -3563,4 +3566,4 @@ class DboSource extends DataSource { } } -} +} \ No newline at end of file diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php index e41567150..6fa681e31 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php @@ -318,8 +318,8 @@ class PostgresTest extends CakeTestCase { $this->assertEquals("0", $this->Dbo->value('0', 'integer')); $this->assertEquals('NULL', $this->Dbo->value('', 'integer')); $this->assertEquals('NULL', $this->Dbo->value('', 'float')); - $this->assertEquals("NULL", $this->Dbo->value('', 'integer', false)); - $this->assertEquals("NULL", $this->Dbo->value('', 'float', false)); + $this->assertEquals('""', $this->Dbo->value('', 'integer', false)); + $this->assertEquals('""', $this->Dbo->value('', 'float', false)); $this->assertEquals("'0.0'", $this->Dbo->value('0.0', 'float')); $this->assertEquals("'TRUE'", $this->Dbo->value('t', 'boolean')); diff --git a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php index dff12ecc5..9b5bf1655 100644 --- a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php @@ -784,6 +784,35 @@ class DboSourceTest extends CakeTestCase { $this->assertTrue($result, 'Query did not return a boolean'); } +/** + * Test NOT NULL on ENUM data type with empty string as a value + * + * @return void + */ + public function testNotNullOnEnum() { + if (!$this->db instanceof Mysql) { + $this->markTestSkipped('This test can only run on MySQL'); + } + $name = $this->db->fullTableName('enum_tests'); + $query = "CREATE TABLE {$name} (mood ENUM('','happy','sad','ok') NOT NULL);"; + $result = $this->db->query($query); + $this->assertTrue($result); + + $EnumTest = ClassRegistry::init('EnumTest'); + $enumResult = $EnumTest->save(array('mood' => '')); + + $query = "DROP TABLE {$name};"; + $result = $this->db->query($query); + $this->assertTrue($result); + + $this->assertEquals(array( + 'EnumTest' => array( + 'mood' => '', + 'id' => '0' + ) + ), $enumResult); + } + /** * test order to generate query order clause for virtual fields *