diff --git a/src/Phinx/Db/Adapter/MysqlAdapter.php b/src/Phinx/Db/Adapter/MysqlAdapter.php index 0dfbb2e37..e2fec36b4 100644 --- a/src/Phinx/Db/Adapter/MysqlAdapter.php +++ b/src/Phinx/Db/Adapter/MysqlAdapter.php @@ -581,7 +581,8 @@ protected function getRenameColumnInstructions(string $tableName, string $column $extra = ' ' . implode(' ', $extras); if (($row['Default'] !== null)) { - $extra .= $this->getDefaultValueDefinition($row['Default']); + $phinxType = $this->getPhinxType($row['Type']); + $extra .= $this->getDefaultValueDefinition($row['Default'], $phinxType['name']); } $definition = $row['Type'] . ' ' . $null . $extra . $comment; diff --git a/src/Phinx/Db/Adapter/PdoAdapter.php b/src/Phinx/Db/Adapter/PdoAdapter.php index 46e6b0870..da0803f70 100644 --- a/src/Phinx/Db/Adapter/PdoAdapter.php +++ b/src/Phinx/Db/Adapter/PdoAdapter.php @@ -725,9 +725,16 @@ public function getAttribute(int $attribute): mixed */ protected function getDefaultValueDefinition(mixed $default, string|Literal|null $columnType = null): string { + $datetimeTypes = [ + static::PHINX_TYPE_DATETIME, + static::PHINX_TYPE_TIMESTAMP, + static::PHINX_TYPE_TIME, + static::PHINX_TYPE_DATE, + ]; + if ($default instanceof Literal) { $default = (string)$default; - } elseif (is_string($default) && stripos($default, 'CURRENT_TIMESTAMP') !== 0) { + } elseif (is_string($default) && (!in_array($columnType, $datetimeTypes) || !preg_match('/^(CURRENT_(TIMESTAMP|TIME|DATE))|(NOW)(\(\d*\))?$/i', $default))) { // Ensure a defaults of CURRENT_TIMESTAMP(3) is not quoted. $default = $this->getConnection()->quote($default); } elseif (is_bool($default)) { diff --git a/src/Phinx/Db/Adapter/SqlServerAdapter.php b/src/Phinx/Db/Adapter/SqlServerAdapter.php index 28a90f1f0..1cfdfee86 100644 --- a/src/Phinx/Db/Adapter/SqlServerAdapter.php +++ b/src/Phinx/Db/Adapter/SqlServerAdapter.php @@ -603,7 +603,7 @@ protected function getChangeDefault(string $tableName, Column $newColumn): Alter if ($default === null) { $default = 'DEFAULT NULL'; } else { - $default = ltrim($this->getDefaultValueDefinition($default)); + $default = ltrim($this->getDefaultValueDefinition($default, $newColumn->getType())); } if (empty($default)) { @@ -1264,7 +1264,7 @@ protected function getColumnSqlDefinition(Column $column, bool $create = true): if ($column->getDefault() === null && $column->isNull()) { $buffer[] = ' DEFAULT NULL'; } else { - $buffer[] = $this->getDefaultValueDefinition($column->getDefault()); + $buffer[] = $this->getDefaultValueDefinition($column->getDefault(), $column->getType()); } } diff --git a/src/Phinx/Db/Table.php b/src/Phinx/Db/Table.php index d0e483390..6647d8d32 100644 --- a/src/Phinx/Db/Table.php +++ b/src/Phinx/Db/Table.php @@ -543,7 +543,9 @@ public function addTimestamps(string|false|null $createdAt = 'created_at', strin throw new RuntimeException('Cannot set both created_at and updated_at columns to false'); } - $columnType = FeatureFlags::$addTimestampsUseDateTime ? 'datetime' : 'timestamp'; + $columnType = FeatureFlags::$addTimestampsUseDateTime + ? AdapterInterface::PHINX_TYPE_DATETIME + : AdapterInterface::PHINX_TYPE_TIMESTAMP; if ($createdAt) { $this->addColumn($createdAt, $columnType, [ diff --git a/tests/Phinx/Db/Adapter/PdoAdapterTest.php b/tests/Phinx/Db/Adapter/PdoAdapterTest.php index 794e096a8..d98685601 100644 --- a/tests/Phinx/Db/Adapter/PdoAdapterTest.php +++ b/tests/Phinx/Db/Adapter/PdoAdapterTest.php @@ -8,6 +8,7 @@ use PDO; use PDOException; use Phinx\Config\Config; +use Phinx\Db\Adapter\AdapterInterface; use Phinx\Util\Literal; use PHPUnit\Framework\TestCase; use ReflectionMethod; @@ -261,4 +262,46 @@ public function testQuoteValueString($input, $expected): void $method = new ReflectionMethod($this->adapter, 'quoteValue'); $this->assertSame($expected, $method->invoke($this->adapter, $input)); } + + public function defaultValueDefinitionDataProvider(): array + { + return [ + ['some string', AdapterInterface::PHINX_TYPE_STRING, " DEFAULT 'some string'"], + [123, AdapterInterface::PHINX_TYPE_INTEGER, ' DEFAULT 123'], + [true, AdapterInterface::PHINX_TYPE_BOOLEAN, ' DEFAULT 1'], + [false, AdapterInterface::PHINX_TYPE_BOOLEAN, ' DEFAULT 0'], + [null, AdapterInterface::PHINX_TYPE_STRING, ''], + [Literal::from('foo'), AdapterInterface::PHINX_TYPE_STRING, ' DEFAULT foo'], + ['CURRENT_TIMESTAMP', AdapterInterface::PHINX_TYPE_STRING, " DEFAULT 'CURRENT_TIMESTAMP'"], + ['CURRENT_TIMESTAMP', AdapterInterface::PHINX_TYPE_DATETIME, ' DEFAULT CURRENT_TIMESTAMP'], + ['CURRENT_TIMESTAMP(3)', AdapterInterface::PHINX_TYPE_DATETIME, ' DEFAULT CURRENT_TIMESTAMP(3)'], + ['CURRENT_TIMESTAMP()', AdapterInterface::PHINX_TYPE_DATETIME, ' DEFAULT CURRENT_TIMESTAMP()'], + ['CURRENT_TIMESTAMP', AdapterInterface::PHINX_TYPE_TIMESTAMP, ' DEFAULT CURRENT_TIMESTAMP'], + ['CURRENT_TIME', AdapterInterface::PHINX_TYPE_TIME, ' DEFAULT CURRENT_TIME'], + ['CURRENT_DATE', AdapterInterface::PHINX_TYPE_DATE, ' DEFAULT CURRENT_DATE'], + ['NOW', AdapterInterface::PHINX_TYPE_DATETIME, ' DEFAULT NOW'], + ]; + } + + /** + * @dataProvider defaultValueDefinitionDataProvider + */ + public function testGetDefaultValueDefinition($input, $columnType, $expected): void + { + /** @var \PDO&\PHPUnit\Framework\MockObject\MockObject $pdo */ + $pdo = $this->getMockBuilder(PDO::class) + ->disableOriginalConstructor() + ->onlyMethods(['quote']) + ->getMock(); + + $pdo->method('quote') + ->willReturnCallback(function (string $input) { + return "'$input'"; + }); + + $this->adapter->setConnection($pdo); + + $method = new ReflectionMethod($this->adapter, 'getDefaultValueDefinition'); + $this->assertSame($expected, $method->invoke($this->adapter, $input, $columnType)); + } }