Browse Source

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

* 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>
tags/2.0.43
egorrishe 3 years ago committed by GitHub
parent
commit
17742cb146
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      framework/CHANGELOG.md
  2. 10
      framework/UPGRADE.md
  3. 7
      framework/db/ColumnSchema.php
  4. 26
      framework/db/ColumnSchemaBuilder.php
  5. 2
      tests/data/mysql.sql
  6. 29
      tests/framework/db/mysql/QueryBuilderTest.php
  7. 26
      tests/framework/db/mysql/SchemaTest.php

1
framework/CHANGELOG.md

@ -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)

10
framework/UPGRADE.md

@ -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
-----------------------

7
framework/db/ColumnSchema.php

@ -154,6 +154,13 @@ class ColumnSchema extends BaseObject
// 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;

26
framework/db/ColumnSchemaBuilder.php

@ -16,6 +16,8 @@ use yii\helpers\StringHelper;
*
* 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
*/
@ -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,
@ -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.
@ -290,6 +294,24 @@ class ColumnSchemaBuilder extends BaseObject
}
/**
* @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
*/

2
tests/data/mysql.sql

@ -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,

29
tests/framework/db/mysql/QueryBuilderTest.php

@ -374,23 +374,22 @@ MySqlStatement;
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
tests/framework/db/mysql/SchemaTest.php

@ -150,6 +150,18 @@ SQL;
'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)',
@ -174,10 +186,24 @@ SQL;
'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';

Loading…
Cancel
Save