diff --git a/.travis.yml b/.travis.yml index bf227a4..faae1f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,4 +45,4 @@ before_script: - psql -U postgres -c 'CREATE DATABASE migrationtest;'; script: -- vendor/bin/phpunit --verbose $PHPUNIT_FLAGS \ No newline at end of file +- vendor/bin/phpunit -v \ No newline at end of file diff --git a/src/Generator.php b/src/Generator.php index f644923..d81bdad 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -9,6 +9,8 @@ use bizley\migration\table\TableIndex; use bizley\migration\table\TablePrimaryKey; use bizley\migration\table\TableStructure; +use Exception; +use PDO; use Yii; use yii\base\Component; use yii\base\InvalidConfigException; @@ -178,6 +180,12 @@ protected function getTableColumns($indexes = [], $schema = null) if ($this->tableSchema instanceof TableSchema) { $indexData = !empty($indexes) ? $indexes : $this->getTableIndexes(); + try { + $version = $this->db->getSlavePdo()->getAttribute(PDO::ATTR_SERVER_VERSION); + } catch (Exception $exception) { + $version = null; + } + foreach ($this->tableSchema->columns as $column) { $isUnique = false; @@ -193,6 +201,7 @@ protected function getTableColumns($indexes = [], $schema = null) 'name' => $column->name, 'type' => $column->type, 'defaultMapping' => $this->db->schema->queryBuilder->typeMap[$column->type], + 'engineVersion' => $version, 'size' => $column->size, 'precision' => $column->precision, 'scale' => $column->scale, diff --git a/src/controllers/MigrationController.php b/src/controllers/MigrationController.php index 5330483..95c6d62 100644 --- a/src/controllers/MigrationController.php +++ b/src/controllers/MigrationController.php @@ -26,13 +26,13 @@ * Generates migration file based on the existing database table and previous migrations. * * @author Paweł Bizley Brzozowski - * @version 2.9.3 + * @version 2.9.4 * @license Apache 2.0 * https://github.com/bizley/yii2-migration */ class MigrationController extends Controller { - protected $version = '2.9.3'; + protected $version = '2.9.4'; /** * @var string Default command action. diff --git a/src/table/TableColumn.php b/src/table/TableColumn.php index 39dbbd3..92a162e 100644 --- a/src/table/TableColumn.php +++ b/src/table/TableColumn.php @@ -103,12 +103,19 @@ class TableColumn extends Object * @since 2.9.0 */ public $after; + /** * @var bool * @since 2.9.0 */ public $isFirst = false; + /** + * @var string + * @since 2.9.4 + */ + public $engineVersion; + /** * Sets length of the column. * @param string|int $value diff --git a/src/table/TableColumnDateTime.php b/src/table/TableColumnDateTime.php index e00063f..e54cc96 100644 --- a/src/table/TableColumnDateTime.php +++ b/src/table/TableColumnDateTime.php @@ -2,6 +2,8 @@ namespace bizley\migration\table; +use yii\db\Expression; + /** * Class TableColumnDateTime * @package bizley\migration\table @@ -14,13 +16,23 @@ class TableColumnDateTime extends TableColumn */ public $lengthSchemas = [TableStructure::SCHEMA_PGSQL]; + public function init() + { + parent::init(); + + if (is_string($this->default) && preg_match('/^current_timestamp\([0-9]*\)$/i', $this->default)) { + // https://github.com/yiisoft/yii2/issues/17744 + $this->default = new Expression($this->default); + } + } + /** * Returns length of the column. * @return int|string */ public function getLength() { - return in_array($this->schema, $this->lengthSchemas, true) ? $this->precision : null; + return $this->isSchemaLengthSupporting() ? $this->precision : null; } /** @@ -29,7 +41,7 @@ public function getLength() */ public function setLength($value) { - if (in_array($this->schema, $this->lengthSchemas, true)) { + if ($this->isSchemaLengthSupporting()) { $this->precision = $value; } } @@ -42,4 +54,17 @@ public function buildSpecificDefinition($table) { $this->definition[] = 'dateTime(' . $this->getRenderLength($table->generalSchema) . ')'; } + + private function isSchemaLengthSupporting() + { + if ( + $this->engineVersion + && $this->schema === TableStructure::SCHEMA_MYSQL + && version_compare($this->engineVersion, '5.6.4', '>=') + ) { + return true; + } + + return in_array($this->schema, $this->lengthSchemas, true); + } } diff --git a/src/table/TableColumnTime.php b/src/table/TableColumnTime.php index f57837a..afc392e 100644 --- a/src/table/TableColumnTime.php +++ b/src/table/TableColumnTime.php @@ -20,7 +20,7 @@ class TableColumnTime extends TableColumn */ public function getLength() { - return in_array($this->schema, $this->lengthSchemas, true) ? $this->precision : null; + return $this->isSchemaLengthSupporting() ? $this->precision : null; } /** @@ -29,7 +29,7 @@ public function getLength() */ public function setLength($value) { - if (in_array($this->schema, $this->lengthSchemas, true)) { + if ($this->isSchemaLengthSupporting()) { $this->precision = $value; } } @@ -42,4 +42,17 @@ public function buildSpecificDefinition($table) { $this->definition[] = 'time(' . $this->getRenderLength($table->generalSchema) . ')'; } + + private function isSchemaLengthSupporting() + { + if ( + $this->engineVersion + && $this->schema === TableStructure::SCHEMA_MYSQL + && version_compare($this->engineVersion, '5.6.4', '>=') + ) { + return true; + } + + return in_array($this->schema, $this->lengthSchemas, true); + } } diff --git a/src/table/TableColumnTimestamp.php b/src/table/TableColumnTimestamp.php index 8253375..0358211 100644 --- a/src/table/TableColumnTimestamp.php +++ b/src/table/TableColumnTimestamp.php @@ -2,6 +2,8 @@ namespace bizley\migration\table; +use yii\db\Expression; + /** * Class TableColumnTimestamp * @package bizley\migration\table @@ -14,13 +16,23 @@ class TableColumnTimestamp extends TableColumn */ public $lengthSchemas = [TableStructure::SCHEMA_PGSQL]; + public function init() + { + parent::init(); + + if (is_string($this->default) && preg_match('/^current_timestamp\([0-9]*\)$/i', $this->default)) { + // https://github.com/yiisoft/yii2/issues/17744 + $this->default = new Expression($this->default); + } + } + /** * Returns length of the column. * @return int|string */ public function getLength() { - return in_array($this->schema, $this->lengthSchemas, true) ? $this->precision : null; + return $this->isSchemaLengthSupporting() ? $this->precision : null; } /** @@ -29,7 +41,7 @@ public function getLength() */ public function setLength($value) { - if (in_array($this->schema, $this->lengthSchemas, true)) { + if ($this->isSchemaLengthSupporting()) { $this->precision = $value; } } @@ -42,4 +54,17 @@ public function buildSpecificDefinition($table) { $this->definition[] = 'timestamp(' . $this->getRenderLength($table->generalSchema) . ')'; } + + private function isSchemaLengthSupporting() + { + if ( + $this->engineVersion + && $this->schema === TableStructure::SCHEMA_MYSQL + && version_compare($this->engineVersion, '5.6.4', '>=') + ) { + return true; + } + + return in_array($this->schema, $this->lengthSchemas, true); + } } diff --git a/tests/table/TableColumnDateTimeTest.php b/tests/table/TableColumnDateTimeTest.php index 9e92a24..562d9c4 100644 --- a/tests/table/TableColumnDateTimeTest.php +++ b/tests/table/TableColumnDateTimeTest.php @@ -33,10 +33,30 @@ public function testDefinitionNoSchema($column, $generalSchema, $result) public function withSchemaDataProvider() { return [ - [['precision' => 4], false, '$this->dateTime(4)'], - [['precision' => 4], true, '$this->dateTime(4)'], - [['precision' => 0], false, '$this->dateTime(0)'], - [['precision' => 0], true, '$this->dateTime(0)'], + [['precision' => 4], false, TableStructure::SCHEMA_PGSQL, '', false, '$this->dateTime(4)'], + [['precision' => 4], true, TableStructure::SCHEMA_PGSQL, '', false, '$this->dateTime(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_PGSQL, '', false, '$this->dateTime(0)'], + [['precision' => 0], true, TableStructure::SCHEMA_PGSQL, '', false, '$this->dateTime(0)'], + [['precision' => 4], false, TableStructure::SCHEMA_PGSQL, '', true, '$this->dateTime(4)'], + [['precision' => 4], true, TableStructure::SCHEMA_PGSQL, '', true, '$this->dateTime(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_PGSQL, '', true, '$this->dateTime(0)'], + [['precision' => 0], true, TableStructure::SCHEMA_PGSQL, '', true, '$this->dateTime()'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '', false, '$this->dateTime()'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '', false, '$this->dateTime()'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '', false, '$this->dateTime()'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '', false, '$this->dateTime()'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '', true, '$this->dateTime()'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '', true, '$this->dateTime()'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '', true, '$this->dateTime()'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '', true, '$this->dateTime()'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->dateTime(4)'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->dateTime(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->dateTime(0)'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->dateTime(0)'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->dateTime(4)'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->dateTime(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->dateTime(0)'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->dateTime()'], ]; } @@ -44,35 +64,16 @@ public function withSchemaDataProvider() * @dataProvider withSchemaDataProvider * @param array $column * @param bool $generalSchema + * @param string $schema + * @param string $version + * @param bool $mapping * @param string $result */ - public function testDefinitionWithSchema($column, $generalSchema, $result) + public function testDefinitionWithSchema($column, $generalSchema, $schema, $version, $mapping, $result) { - $column['schema'] = TableStructure::SCHEMA_PGSQL; - $column = new TableColumnDateTime($column); - $this->assertEquals($result, $column->renderDefinition($this->getTable($generalSchema))); - } - - public function withMappingAndSchemaDataProvider() - { - return [ - [['precision' => 4], false, '$this->dateTime(4)'], - [['precision' => 4], true, '$this->dateTime(4)'], - [['precision' => 0], false, '$this->dateTime(0)'], - [['precision' => 0], true, '$this->dateTime()'], - ]; - } - - /** - * @dataProvider withMappingAndSchemaDataProvider - * @param array $column - * @param bool $generalSchema - * @param string $result - */ - public function testDefinitionWithMappingAndSchema($column, $generalSchema, $result) - { - $column['schema'] = TableStructure::SCHEMA_PGSQL; - $column['defaultMapping'] = 'timestamp(0)'; + $column['schema'] = $schema; + $column['engineVersion'] = $version; + $column['defaultMapping'] = $mapping ? 'datetime(0)' : null; $column = new TableColumnDateTime($column); $this->assertEquals($result, $column->renderDefinition($this->getTable($generalSchema))); } diff --git a/tests/table/TableColumnTimeTest.php b/tests/table/TableColumnTimeTest.php index 1aaa359..a0b9529 100644 --- a/tests/table/TableColumnTimeTest.php +++ b/tests/table/TableColumnTimeTest.php @@ -33,10 +33,30 @@ public function testDefinitionNoSchema($column, $generalSchema, $result) public function withSchemaDataProvider() { return [ - [['precision' => 0], false, '$this->time(0)'], - [['precision' => 4], false, '$this->time(4)'], - [['precision' => 0], true, '$this->time(0)'], - [['precision' => 4], true, '$this->time(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_PGSQL, '', false, '$this->time(0)'], + [['precision' => 4], false, TableStructure::SCHEMA_PGSQL, '', false, '$this->time(4)'], + [['precision' => 0], true, TableStructure::SCHEMA_PGSQL, '', false, '$this->time(0)'], + [['precision' => 4], true, TableStructure::SCHEMA_PGSQL, '', false, '$this->time(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_PGSQL, '', true, '$this->time(0)'], + [['precision' => 4], false, TableStructure::SCHEMA_PGSQL, '', true, '$this->time(4)'], + [['precision' => 0], true, TableStructure::SCHEMA_PGSQL, '', true, '$this->time()'], + [['precision' => 4], true, TableStructure::SCHEMA_PGSQL, '', true, '$this->time(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '', false, '$this->time()'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '', false, '$this->time()'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '', false, '$this->time()'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '', false, '$this->time()'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '', true, '$this->time()'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '', true, '$this->time()'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '', true, '$this->time()'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '', true, '$this->time()'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->time(0)'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->time(4)'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->time(0)'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->time(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->time(0)'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->time(4)'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->time()'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->time(4)'], ]; } @@ -44,35 +64,16 @@ public function withSchemaDataProvider() * @dataProvider withSchemaDataProvider * @param array $column * @param bool $generalSchema + * @param string $schema + * @param string $version + * @param bool $mapping * @param string $result */ - public function testDefinitionWithSchema($column, $generalSchema, $result) + public function testDefinitionWithSchema($column, $generalSchema, $schema, $version, $mapping, $result) { - $column['schema'] = TableStructure::SCHEMA_PGSQL; - $column = new TableColumnTime($column); - $this->assertEquals($result, $column->renderDefinition($this->getTable($generalSchema))); - } - - public function withMappingAndSchemaDataProvider() - { - return [ - [['precision' => 0], false, '$this->time(0)'], - [['precision' => 4], false, '$this->time(4)'], - [['precision' => 0], true, '$this->time()'], - [['precision' => 4], true, '$this->time(4)'], - ]; - } - - /** - * @dataProvider withMappingAndSchemaDataProvider - * @param array $column - * @param bool $generalSchema - * @param string $result - */ - public function testDefinitionWithMappingAndSchema($column, $generalSchema, $result) - { - $column['schema'] = TableStructure::SCHEMA_PGSQL; - $column['defaultMapping'] = 'time(0)'; + $column['schema'] = $schema; + $column['engineVersion'] = $version; + $column['defaultMapping'] = $mapping ? 'time(0)' : null; $column = new TableColumnTime($column); $this->assertEquals($result, $column->renderDefinition($this->getTable($generalSchema))); } diff --git a/tests/table/TableColumnTimestampTest.php b/tests/table/TableColumnTimestampTest.php index c7c09d1..66a88c2 100644 --- a/tests/table/TableColumnTimestampTest.php +++ b/tests/table/TableColumnTimestampTest.php @@ -33,10 +33,30 @@ public function testDefinitionNoSchema($column, $generalSchema, $result) public function withSchemaDataProvider() { return [ - [['precision' => 0], false, '$this->timestamp(0)'], - [['precision' => 4], false, '$this->timestamp(4)'], - [['precision' => 0], true, '$this->timestamp(0)'], - [['precision' => 4], true, '$this->timestamp(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_PGSQL, '', false, '$this->timestamp(0)'], + [['precision' => 4], false, TableStructure::SCHEMA_PGSQL, '', false, '$this->timestamp(4)'], + [['precision' => 0], true, TableStructure::SCHEMA_PGSQL, '', false, '$this->timestamp(0)'], + [['precision' => 4], true, TableStructure::SCHEMA_PGSQL, '', false, '$this->timestamp(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_PGSQL, '', true, '$this->timestamp(0)'], + [['precision' => 4], false, TableStructure::SCHEMA_PGSQL, '', true, '$this->timestamp(4)'], + [['precision' => 0], true, TableStructure::SCHEMA_PGSQL, '', true, '$this->timestamp()'], + [['precision' => 4], true, TableStructure::SCHEMA_PGSQL, '', true, '$this->timestamp(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '', false, '$this->timestamp()'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '', false, '$this->timestamp()'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '', false, '$this->timestamp()'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '', false, '$this->timestamp()'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '', true, '$this->timestamp()'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '', true, '$this->timestamp()'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '', true, '$this->timestamp()'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '', true, '$this->timestamp()'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->timestamp(0)'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->timestamp(4)'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->timestamp(0)'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '5.6.4', false, '$this->timestamp(4)'], + [['precision' => 0], false, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->timestamp(0)'], + [['precision' => 4], false, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->timestamp(4)'], + [['precision' => 0], true, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->timestamp()'], + [['precision' => 4], true, TableStructure::SCHEMA_MYSQL, '5.6.4', true, '$this->timestamp(4)'], ]; } @@ -44,35 +64,16 @@ public function withSchemaDataProvider() * @dataProvider withSchemaDataProvider * @param array $column * @param bool $generalSchema + * @param string $schema + * @param string $version + * @param bool $mapping * @param string $result */ - public function testDefinitionWithSchema($column, $generalSchema, $result) + public function testDefinitionWithSchema($column, $generalSchema, $schema, $version, $mapping, $result) { - $column['schema'] = TableStructure::SCHEMA_PGSQL; - $column = new TableColumnTimestamp($column); - $this->assertEquals($result, $column->renderDefinition($this->getTable($generalSchema))); - } - - public function withMappingAndSchemaDataProvider() - { - return [ - [['precision' => 0], false, '$this->timestamp(0)'], - [['precision' => 4], false, '$this->timestamp(4)'], - [['precision' => 0], true, '$this->timestamp()'], - [['precision' => 4], true, '$this->timestamp(4)'], - ]; - } - - /** - * @dataProvider withMappingAndSchemaDataProvider - * @param array $column - * @param bool $generalSchema - * @param string $result - */ - public function testDefinitionWithMappingAndSchema($column, $generalSchema, $result) - { - $column['schema'] = TableStructure::SCHEMA_PGSQL; - $column['defaultMapping'] = 'timestamp(0)'; + $column['schema'] = $schema; + $column['engineVersion'] = $version; + $column['defaultMapping'] = $mapping ? 'timestamp(0)' : null; $column = new TableColumnTimestamp($column); $this->assertEquals($result, $column->renderDefinition($this->getTable($generalSchema))); }