Skip to content

Commit

Permalink
Fixes #14367: In yii\db\mysql\QueryBuilder added support fractional…
Browse files Browse the repository at this point in the history
… seconds for time types for MySQL >= 5.6.4
  • Loading branch information
kos-v authored and samdark committed Oct 11, 2018
1 parent 5d7c5f8 commit 9f383ab
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 11 deletions.
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@ Yii Framework 2 Change Log
2.0.16 under development
------------------------

- Enh #14367: In `yii\db\mysql\QueryBuilder` added support fractional seconds for time types for MySQL >= 5.6.4 (konstantin-vl)
- Bug #16766: `yii\filters\ContentNegotiator` was not setting `Vary` header to inform cache recipients (koteq, cebe, samdark)
- Bug #11960: Fixed `checked` option ignore in `yii\helpers\BaseHtml::checkbox()` (misantron)
- Bug #14759: Fixed `yii\web\JsonResponseFormatter` output for `null` data (misantron)
Expand Down
49 changes: 46 additions & 3 deletions framework/db/mysql/QueryBuilder.php
Expand Up @@ -39,16 +39,22 @@ class QueryBuilder extends \yii\db\QueryBuilder
Schema::TYPE_FLOAT => 'float',
Schema::TYPE_DOUBLE => 'double',
Schema::TYPE_DECIMAL => 'decimal(10,0)',
Schema::TYPE_DATETIME => 'datetime',
Schema::TYPE_TIMESTAMP => 'timestamp',
Schema::TYPE_TIME => 'time',
Schema::TYPE_DATE => 'date',
Schema::TYPE_BINARY => 'blob',
Schema::TYPE_BOOLEAN => 'tinyint(1)',
Schema::TYPE_MONEY => 'decimal(19,4)',
Schema::TYPE_JSON => 'json'
];

/**
* {@inheritdoc}
*/
public function init()
{
parent::init();

$this->typeMap = array_merge($this->typeMap, $this->defaultTimeTypeMap());
}

/**
* {@inheritdoc}
Expand Down Expand Up @@ -362,4 +368,41 @@ private function getColumnDefinition($table, $column)
return null;
}

/**
* Checks the ability to use fractional seconds.
*
* @return bool
* @see https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
*/
private function supportsFractionalSeconds()
{
$version = $this->db->getSlavePdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
return version_compare($version, '5.6.4', '>=');
}

/**
* Returns the map for default time type.
* If the version of MySQL is lower than 5.6.4, then the types will be without fractional seconds,
* otherwise with fractional seconds.
*
* @return array
*/
private function defaultTimeTypeMap()
{
$map = [
Schema::TYPE_DATETIME => 'datetime',
Schema::TYPE_TIMESTAMP => 'timestamp',
Schema::TYPE_TIME => 'time',
];

if ($this->supportsFractionalSeconds()) {
$map = [
Schema::TYPE_DATETIME => 'datetime(0)',
Schema::TYPE_TIMESTAMP => 'timestamp(0)',
Schema::TYPE_TIME => 'time(0)',
];
}

return $map;
}
}
6 changes: 0 additions & 6 deletions tests/framework/db/QueryBuilderTest.php
Expand Up @@ -280,7 +280,6 @@ public function columnTypes()
Schema::TYPE_DATETIME . ' NOT NULL',
$this->dateTime()->notNull(),
[
'mysql' => 'datetime NOT NULL',
'postgres' => 'timestamp(0) NOT NULL',
'sqlite' => 'datetime NOT NULL',
'oci' => 'TIMESTAMP NOT NULL',
Expand All @@ -292,7 +291,6 @@ public function columnTypes()
Schema::TYPE_DATETIME,
$this->dateTime(),
[
'mysql' => 'datetime',
'postgres' => 'timestamp(0)',
'sqlite' => 'datetime',
'oci' => 'TIMESTAMP',
Expand Down Expand Up @@ -871,7 +869,6 @@ public function columnTypes()
Schema::TYPE_TIME . ' NOT NULL',
$this->time()->notNull(),
[
'mysql' => 'time NOT NULL',
'postgres' => 'time(0) NOT NULL',
'sqlite' => 'time NOT NULL',
'oci' => 'TIMESTAMP NOT NULL',
Expand All @@ -883,7 +880,6 @@ public function columnTypes()
Schema::TYPE_TIME,
$this->time(),
[
'mysql' => 'time',
'postgres' => 'time(0)',
'sqlite' => 'time',
'oci' => 'TIMESTAMP',
Expand All @@ -906,7 +902,6 @@ public function columnTypes()
Schema::TYPE_TIMESTAMP . ' NOT NULL',
$this->timestamp()->notNull(),
[
'mysql' => 'timestamp NOT NULL',
'postgres' => 'timestamp(0) NOT NULL',
'sqlite' => 'timestamp NOT NULL',
'oci' => 'TIMESTAMP NOT NULL',
Expand Down Expand Up @@ -934,7 +929,6 @@ public function columnTypes()
Schema::TYPE_TIMESTAMP . ' NULL DEFAULT NULL',
$this->timestamp()->defaultValue(null),
[
'mysql' => 'timestamp NULL DEFAULT NULL',
'postgres' => 'timestamp(0) NULL DEFAULT NULL',
'sqlite' => 'timestamp NULL DEFAULT NULL',
'sqlsrv' => 'timestamp NULL DEFAULT NULL',
Expand Down
62 changes: 60 additions & 2 deletions tests/framework/db/mysql/QueryBuilderTest.php
Expand Up @@ -85,6 +85,64 @@ public function columnTypes()
];
}

return array_merge(parent::columnTypes(), $this->columnTimeTypes(), $columns);
}

public function columnTimeTypes()
{
$columns = [
[
Schema::TYPE_DATETIME . ' NOT NULL',
$this->dateTime()->notNull(),
'datetime NOT NULL',
],
[
Schema::TYPE_DATETIME,
$this->dateTime(),
'datetime',
],
[
Schema::TYPE_TIME . ' NOT NULL',
$this->time()->notNull(),
'time NOT NULL',
],
[
Schema::TYPE_TIME,
$this->time(),
'time',
],
[
Schema::TYPE_TIMESTAMP . ' NOT NULL',
$this->timestamp()->notNull(),
'timestamp NOT NULL',
],
[
Schema::TYPE_TIMESTAMP . ' NULL DEFAULT NULL',
$this->timestamp()->defaultValue(null),
'timestamp NULL DEFAULT NULL',
],
];

/**
* @link https://github.com/yiisoft/yii2/issues/14367
*/
$mysqlVersion = $this->getDb()->getSlavePdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
$supportsFractionalSeconds = version_compare($mysqlVersion,'5.6.4', '>=');
if ($supportsFractionalSeconds) {
$expectedValues = [
'datetime(0) NOT NULL',
'datetime(0)',
'time(0) NOT NULL',
'time(0)',
'timestamp(0) NOT NULL',
'timestamp(0) NULL DEFAULT NULL',
];

foreach ($expectedValues as $index => $expected) {
$columns[$index][2] = $expected;
}
}

/**
* @link https://github.com/yiisoft/yii2/issues/14834
*/
Expand All @@ -99,11 +157,11 @@ public function columnTypes()
$columns[] = [
Schema::TYPE_TIMESTAMP,
$this->timestamp(),
'timestamp',
$supportsFractionalSeconds ? 'timestamp(0)' : 'timestamp',
];
}

return array_merge(parent::columnTypes(), $columns);
return $columns;
}

public function primaryKeysProvider()
Expand Down

0 comments on commit 9f383ab

Please sign in to comment.