Skip to content

Commit

Permalink
don't convert int to string if db type of column is numeric (#18741)
Browse files Browse the repository at this point in the history
* write adequate test for issue #14663

* don't convert int to string if db type of column is numeric (#14663)

* fix bigint schema test for MySql >8.0.17 (#14663)

* Update CHANGELOG.md

* Update CHANGELOG.md

* update phpdoc [ci skip] (#14663)

* refactoring test case to make it clearer [ci skip] (#14663)

* check `int unsigned` in `QueryBuilderTest::testInsertInteger()` (#14663)

* Update Upgrade.md (#14663)

* fix `int unsigned` schema test for MySql >8.0.17 (#14663)

* fix `int unsigned` schema test for MySql <5.7 (#14663)

Co-authored-by: Alexander Makarov <sam@rmcreative.ru>
Co-authored-by: Bizley <pawel@positive.codes>
  • Loading branch information
3 people authored Jul 6, 2021
1 parent 8d43241 commit 17742cb
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 17 deletions.
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Yii Framework 2 Change Log
2.0.43 under development
------------------------

- Bug #14663: Do not convert int to string if database type of a column is numeric (egorrishe)
- Bug #18650: Refactor `framework/assets/yii.activeForm.js` arrow function into traditional function for IE11 compatibility (marcovtwout)
- Enh #18724: Allow jQuery 3.6 to be installed (marcovtwout)
- Enh #18628: Added strings "software", and "hardware" to `$specials` array in `yii\helpers\BaseInflector` (kjusupov)
Expand Down
10 changes: 10 additions & 0 deletions framework/UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ Upgrade from Yii 2.0.42
-----------------------

* `yii\base\ErrorHandler` does not expose the `$_SERVER` information implicitely anymore.
* The methods `phpTypecast()` and `dbTypecast()` of `yii\db\ColumnSchema` will no longer convert `$value` from `int` to
`string`, if database column type is `INTEGER UNSIGNED` or `BIGINT UNSIGNED`.
* I.e. it affects update and insert queries. For example:
```php
\Yii::$app->db->createCommand()->insert('{{some_table}}', ['int_unsigned_col' => 22])->execute();
```
will execute next SQL:
```sql
INSERT INTO `some_table` (`int_unsigned_col`) VALUES (22)
```

Upgrade from Yii 2.0.41
-----------------------
Expand Down
7 changes: 7 additions & 0 deletions framework/db/ColumnSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,13 @@ protected function typecast($value)
// ensure type cast always has . as decimal separator in all locales
return StringHelper::floatToString($value);
}
if (is_numeric($value)
&& ColumnSchemaBuilder::CATEGORY_NUMERIC === ColumnSchemaBuilder::$typeCategoryMap[$this->type]
) {
// https://github.com/yiisoft/yii2/issues/14663
return $value;
}

return (string) $value;
case 'integer':
return (int) $value;
Expand Down
26 changes: 24 additions & 2 deletions framework/db/ColumnSchemaBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*
* See [[SchemaBuilderTrait]] for more detailed description and usage examples.
*
* @property array $categoryMap mapping of abstract column types (keys) to type categories (values). (since version 2.0.8)
*
* @author Vasenin Matvey <vaseninm@gmail.com>
* @since 2.0.6
*/
Expand Down Expand Up @@ -81,9 +83,9 @@ class ColumnSchemaBuilder extends BaseObject

/**
* @var array mapping of abstract column types (keys) to type categories (values).
* @since 2.0.8
* @since 2.0.43
*/
public $categoryMap = [
public static $typeCategoryMap = [
Schema::TYPE_PK => self::CATEGORY_PK,
Schema::TYPE_UPK => self::CATEGORY_PK,
Schema::TYPE_BIGPK => self::CATEGORY_PK,
Expand All @@ -106,6 +108,8 @@ class ColumnSchemaBuilder extends BaseObject
Schema::TYPE_BOOLEAN => self::CATEGORY_NUMERIC,
Schema::TYPE_MONEY => self::CATEGORY_NUMERIC,
];


/**
* @var \yii\db\Connection the current database connection. It is used mainly to escape strings
* safely when building the final column schema string.
Expand Down Expand Up @@ -289,6 +293,24 @@ public function __toString()
return $this->buildCompleteString($format);
}

/**
* @return array mapping of abstract column types (keys) to type categories (values).
* @since 2.0.43
*/
public function getCategoryMap()
{
return static::$typeCategoryMap;
}

/**
* @param array $categoryMap mapping of abstract column types (keys) to type categories (values).
* @since 2.0.43
*/
public function setCategoryMap($categoryMap)
{
static::$typeCategoryMap = $categoryMap;
}

/**
* Builds the length/precision part of the column.
* @return string
Expand Down
2 changes: 2 additions & 0 deletions tests/data/mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,10 @@ CREATE TABLE `negative_default_values` (
CREATE TABLE `type` (
`int_col` integer NOT NULL,
`int_col2` integer DEFAULT '1',
`int_col3` integer(11) unsigned DEFAULT '1',
`tinyint_col` tinyint(3) DEFAULT '1',
`smallint_col` smallint(1) DEFAULT '1',
`bigint_col` bigint unsigned,
`char_col` char(100) NOT NULL,
`char_col2` varchar(100) DEFAULT 'something',
`char_col3` text,
Expand Down
29 changes: 14 additions & 15 deletions tests/framework/db/mysql/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -374,23 +374,22 @@ public function testIssue17449()
public function testInsertInteger()
{
$db = $this->getConnection();

$command = $db->createCommand();

$sql = $command->insert(
'{{customer}}',
[
'profile_id' => 22,
]
)->getRawSql();
$this->assertEquals('INSERT INTO `customer` (`profile_id`) VALUES (22)', $sql);
// int value should not be converted to string, when column is `int`
$sql = $command->insert('{{type}}', ['int_col' => 22])->getRawSql();
$this->assertEquals('INSERT INTO `type` (`int_col`) VALUES (22)', $sql);

$sql = $command->insert(
'{{customer}}',
[
'profile_id' => '1000000000000',
]
)->getRawSql();
$this->assertEquals('INSERT INTO `customer` (`profile_id`) VALUES (1000000000000)', $sql);
// int value should not be converted to string, when column is `int unsigned`
$sql = $command->insert('{{type}}', ['int_col3' => 22])->getRawSql();
$this->assertEquals('INSERT INTO `type` (`int_col3`) VALUES (22)', $sql);

// int value should not be converted to string, when column is `bigint unsigned`
$sql = $command->insert('{{type}}', ['bigint_col' => 22])->getRawSql();
$this->assertEquals("INSERT INTO `type` (`bigint_col`) VALUES (22)", $sql);

// string value should not be converted
$sql = $command->insert('{{type}}', ['bigint_col' => '1000000000000'])->getRawSql();
$this->assertEquals("INSERT INTO `type` (`bigint_col`) VALUES ('1000000000000')", $sql);
}
}
26 changes: 26 additions & 0 deletions tests/framework/db/mysql/SchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ public function getExpectedColumns()
'scale' => null,
'defaultValue' => 1,
],
'int_col3' => [
'type' => 'integer',
'dbType' => \version_compare($version, '8.0.17', '>') ? 'int unsigned' : 'int(11) unsigned',
'phpType' => 'integer',
'allowNull' => true,
'autoIncrement' => false,
'enumValues' => null,
'size' => \version_compare($version, '8.0.17', '>') ? null : 11,
'precision' => \version_compare($version, '8.0.17', '>') ? null : 11,
'scale' => null,
'defaultValue' => 1,
],
'tinyint_col' => [
'type' => 'tinyint',
'dbType' => \version_compare($version, '8.0.17', '>') ? 'tinyint' : 'tinyint(3)',
Expand All @@ -174,10 +186,24 @@ public function getExpectedColumns()
'scale' => null,
'defaultValue' => 1,
],
'bigint_col' => [
'type' => 'bigint',
'dbType' => \version_compare($version, '8.0.17', '>') ? 'bigint unsigned' : 'bigint(20) unsigned',
'phpType' => 'string',
'allowNull' => true,
'autoIncrement' => false,
'enumValues' => null,
'size' => \version_compare($version, '8.0.17', '>') ? null : 20,
'precision' => \version_compare($version, '8.0.17', '>') ? null : 20,
'scale' => null,
'defaultValue' => null,
],
]
);

if (version_compare($version, '5.7', '<')) {
$columns['int_col3']['phpType'] = 'string';

$columns['json_col']['type'] = 'text';
$columns['json_col']['dbType'] = 'longtext';
$columns['json_col']['phpType'] = 'string';
Expand Down

0 comments on commit 17742cb

Please # to comment.