Skip to content

Commit f79aeb8

Browse files
authored
[10.x] Fix: select maximum supported timestamp precision (#44223)
* fix: select maximum supported timestamp precision Simplified code, upgraded from deprecations * added test * removed further deprecations * added back depracations Until DBAL reaches v4 * styleci fixes
1 parent 8ec8c81 commit f79aeb8

File tree

2 files changed

+60
-35
lines changed

2 files changed

+60
-35
lines changed

src/Illuminate/Database/DBAL/TimestampType.php

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,60 @@
44

55
use Doctrine\DBAL\Exception as DBALException;
66
use Doctrine\DBAL\Platforms\AbstractPlatform;
7+
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
8+
use Doctrine\DBAL\Platforms\MariaDBPlatform;
9+
use Doctrine\DBAL\Platforms\MySQL57Platform;
10+
use Doctrine\DBAL\Platforms\MySQL80Platform;
11+
use Doctrine\DBAL\Platforms\MySQLPlatform;
12+
use Doctrine\DBAL\Platforms\PostgreSQL100Platform;
13+
use Doctrine\DBAL\Platforms\PostgreSQL94Platform;
14+
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
15+
use Doctrine\DBAL\Platforms\SqlitePlatform;
16+
use Doctrine\DBAL\Platforms\SQLServer2012Platform;
17+
use Doctrine\DBAL\Platforms\SQLServerPlatform;
718
use Doctrine\DBAL\Types\PhpDateTimeMappingType;
819
use Doctrine\DBAL\Types\Type;
920

1021
class TimestampType extends Type implements PhpDateTimeMappingType
1122
{
1223
/**
1324
* {@inheritdoc}
25+
*
26+
* @throws DBALException
1427
*/
15-
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
28+
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
1629
{
17-
return match ($name = $platform->getName()) {
18-
'mysql',
19-
'mysql2' => $this->getMySqlPlatformSQLDeclaration($fieldDeclaration),
20-
'postgresql',
21-
'pgsql',
22-
'postgres' => $this->getPostgresPlatformSQLDeclaration($fieldDeclaration),
23-
'mssql' => $this->getSqlServerPlatformSQLDeclaration($fieldDeclaration),
24-
'sqlite',
25-
'sqlite3' => $this->getSQLitePlatformSQLDeclaration($fieldDeclaration),
26-
default => throw new DBALException('Invalid platform: '.$name),
30+
return match (get_class($platform)) {
31+
MySQLPlatform::class,
32+
MySQL57Platform::class,
33+
MySQL80Platform::class,
34+
MariaDBPlatform::class,
35+
MariaDb1027Platform::class => $this->getMySqlPlatformSQLDeclaration($column),
36+
PostgreSQLPlatform::class,
37+
PostgreSQL94Platform::class,
38+
PostgreSQL100Platform::class => $this->getPostgresPlatformSQLDeclaration($column),
39+
SQLServerPlatform::class,
40+
SQLServer2012Platform::class => $this->getSqlServerPlatformSQLDeclaration($column),
41+
SqlitePlatform::class => 'DATETIME',
42+
default => throw new DBALException('Invalid platform: '.substr(strrchr(get_class($platform), '\\'), 1)),
2743
};
2844
}
2945

3046
/**
3147
* Get the SQL declaration for MySQL.
3248
*
33-
* @param array $fieldDeclaration
49+
* @param array $column
3450
* @return string
3551
*/
36-
protected function getMySqlPlatformSQLDeclaration(array $fieldDeclaration)
52+
protected function getMySqlPlatformSQLDeclaration(array $column): string
3753
{
3854
$columnType = 'TIMESTAMP';
3955

40-
if ($fieldDeclaration['precision']) {
41-
$columnType = 'TIMESTAMP('.$fieldDeclaration['precision'].')';
56+
if ($column['precision']) {
57+
$columnType = 'TIMESTAMP('.min((int) $column['precision'], 6).')';
4258
}
4359

44-
$notNull = $fieldDeclaration['notnull'] ?? false;
60+
$notNull = $column['notnull'] ?? false;
4561

4662
if (! $notNull) {
4763
return $columnType.' NULL';
@@ -53,36 +69,25 @@ protected function getMySqlPlatformSQLDeclaration(array $fieldDeclaration)
5369
/**
5470
* Get the SQL declaration for PostgreSQL.
5571
*
56-
* @param array $fieldDeclaration
72+
* @param array $column
5773
* @return string
5874
*/
59-
protected function getPostgresPlatformSQLDeclaration(array $fieldDeclaration)
75+
protected function getPostgresPlatformSQLDeclaration(array $column): string
6076
{
61-
return 'TIMESTAMP('.(int) $fieldDeclaration['precision'].')';
77+
return 'TIMESTAMP('.min((int) $column['precision'], 6).')';
6278
}
6379

6480
/**
6581
* Get the SQL declaration for SQL Server.
6682
*
67-
* @param array $fieldDeclaration
68-
* @return string
69-
*/
70-
protected function getSqlServerPlatformSQLDeclaration(array $fieldDeclaration)
71-
{
72-
return $fieldDeclaration['precision'] ?? false
73-
? 'DATETIME2('.$fieldDeclaration['precision'].')'
74-
: 'DATETIME';
75-
}
76-
77-
/**
78-
* Get the SQL declaration for SQLite.
79-
*
80-
* @param array $fieldDeclaration
83+
* @param array $column
8184
* @return string
8285
*/
83-
protected function getSQLitePlatformSQLDeclaration(array $fieldDeclaration)
86+
protected function getSqlServerPlatformSQLDeclaration(array $column): string
8487
{
85-
return 'DATETIME';
88+
return $column['precision'] ?? false
89+
? 'DATETIME2('.min((int) $column['precision'], 7).')'
90+
: 'DATETIME';
8691
}
8792

8893
/**

tests/Database/DatabaseSchemaBlueprintIntegrationTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,26 @@ public function testItEnsuresRenamingAndDroppingMultipleColumnsIsAvailable()
404404
});
405405
}
406406

407+
public function testItDoesNotSetPrecisionHigherThanSupportedWhenRenamingTimestamps()
408+
{
409+
$this->db->connection()->getSchemaBuilder()->create('users', function (Blueprint $table) {
410+
$table->timestamp('created_at');
411+
});
412+
413+
try {
414+
// this would only fail in mysql, postgres and sql server
415+
$this->db->connection()->getSchemaBuilder()->table('users', function (Blueprint $table) {
416+
$table->renameColumn('created_at', 'new_created_at');
417+
});
418+
$this->addToAssertionCount(1); // it did not throw
419+
} catch (\Exception $e) {
420+
// Expecting something similar to:
421+
// Illuminate\Database\QueryException
422+
// SQLSTATE[42000]: Syntax error or access violation: 1426 Too big precision 10 specified for 'my_timestamp'. Maximum is 6....
423+
$this->fail('test_it_does_not_set_precision_higher_than_supported_when_renaming_timestamps has failed. Error: '.$e->getMessage());
424+
}
425+
}
426+
407427
public function testItEnsuresDroppingForeignKeyIsAvailable()
408428
{
409429
$this->expectException(BadMethodCallException::class);

0 commit comments

Comments
 (0)