Fixed batchInsert casting of double values according to locale (#14448)

fixes #6526
This commit is contained in:
Carsten Brandt
2017-08-13 22:15:04 +02:00
committed by GitHub
parent 03299e8870
commit cda3089623
6 changed files with 68 additions and 0 deletions

View File

@ -4,6 +4,7 @@ Yii Framework 2 Change Log
2.0.13 under development
------------------------
- Bug #6526: Fixed `yii\db\Command::batchInsert()` casting of double values correctly independent of the locale (cebe, leammas)
- Bug #14542: Ensured only ASCII characters are in CSRF cookie value since binary data causes issues with ModSecurity and some browsers (samdark)
- Enh #14022: `yii\web\UrlManager::setBaseUrl()` now supports aliases (dmirogin)
- Bug #14471: `ContentNegotiator` will always set one of the configured server response formats even if the client does not accept any of them (PowerGamer1)

View File

@ -278,6 +278,9 @@ class QueryBuilder extends \yii\base\BaseObject
}
if (is_string($value)) {
$value = $schema->quoteValue($value);
} elseif (is_float($value)) {
// ensure type cast always has . as decimal separator in all locales
$value = str_replace(',', '.', (string) $value);
} elseif ($value === false) {
$value = 0;
} elseif ($value === null) {

View File

@ -268,6 +268,9 @@ EOD;
}
if (is_string($value)) {
$value = $schema->quoteValue($value);
} elseif (is_float($value)) {
// ensure type cast always has . as decimal separator in all locales
$value = str_replace(',', '.', (string) $value);
} elseif ($value === false) {
$value = 0;
} elseif ($value === null) {

View File

@ -305,6 +305,9 @@ class QueryBuilder extends \yii\db\QueryBuilder
}
if (is_string($value)) {
$value = $schema->quoteValue($value);
} elseif (is_float($value)) {
// ensure type cast always has . as decimal separator in all locales
$value = str_replace(',', '.', (string) $value);
} elseif ($value === true) {
$value = 'TRUE';
} elseif ($value === false) {

View File

@ -101,6 +101,9 @@ class QueryBuilder extends \yii\db\QueryBuilder
}
if (is_string($value)) {
$value = $schema->quoteValue($value);
} elseif (is_float($value)) {
// ensure type cast always has . as decimal separator in all locales
$value = str_replace(',', '.', (string) $value);
} elseif ($value === false) {
$value = 0;
} elseif ($value === null) {

View File

@ -312,6 +312,61 @@ SQL;
}
}
/**
* Test batch insert with different data types.
*
* Ensure double is inserted with `.` decimal separator.
*
* https://github.com/yiisoft/yii2/issues/6526
*/
public function testBatchInsertDataTypesLocale()
{
$locale = setlocale(LC_NUMERIC, 0);
if (false === $locale) {
$this->markTestSkipped('Your platform does not support locales.');
}
$db = $this->getConnection();
try {
// This one sets decimal mark to comma sign
setlocale(LC_NUMERIC, 'ru_RU.utf8');
$cols = ['int_col', 'char_col', 'float_col', 'bool_col'];
$data = [
[1, 'A', 9.735, true],
[2, 'B', -2.123, false],
[3, 'C', 2.123, false],
];
// clear data in "type" table
$db->createCommand()->delete('type')->execute();
// batch insert on "type" table
$db->createCommand()->batchInsert('type', $cols, $data)->execute();
$data = $db->createCommand("SELECT * FROM {{type}} WHERE [[int_col]] IN (1,2,3) ORDER BY [[int_col]];")->queryAll();
$this->assertEquals(3, count($data));
$this->assertEquals(1, $data[0]['int_col']);
$this->assertEquals(2, $data[1]['int_col']);
$this->assertEquals(3, $data[2]['int_col']);
$this->assertEquals('A', rtrim($data[0]['char_col'])); // rtrim because Postgres padds the column with whitespace
$this->assertEquals('B', rtrim($data[1]['char_col']));
$this->assertEquals('C', rtrim($data[2]['char_col']));
$this->assertEquals('9.735', $data[0]['float_col']);
$this->assertEquals('-2.123', $data[1]['float_col']);
$this->assertEquals('2.123', $data[2]['float_col']);
$this->assertEquals('1', $data[0]['bool_col']);
$this->assertIsOneOf($data[1]['bool_col'], ['0', false]);
$this->assertIsOneOf($data[2]['bool_col'], ['0', false]);
} catch (\Exception $e) {
setlocale(LC_NUMERIC, $locale);
throw $e;
} catch (\Throwable $e) {
setlocale(LC_NUMERIC, $locale);
throw $e;
}
}
public function testInsert()
{
$db = $this->getConnection();