Skip to content

Commit 7bdc30e

Browse files
authored
Add DEFAULT support for CURRENT_DATE, CURRENT_TIME, LOCALTIME, LOCALTIMESTAMP (#963)
Add DEFAULT support for CURRENT_DATE, CURRENT_TIME, LOCALTIME, LOCALTIMESTAMP Expand automatic SQL function handling in getDefaultValueDefinition() to support more standard SQL datetime functions without requiring Literal::from(): - CURRENT_DATE for date columns - CURRENT_TIME for time columns - LOCALTIME for time columns - LOCALTIMESTAMP for datetime/timestamp columns Each function is only unquoted when used with appropriate column types. Using them with incompatible types (e.g., CURRENT_DATE on a string column) will quote the value as a literal string.
1 parent b037e78 commit 7bdc30e

File tree

3 files changed

+77
-9
lines changed

3 files changed

+77
-9
lines changed

docs/en/writing-migrations.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,32 @@ appropriate for the integer size, so that ``smallinteger`` will give you
287287
``smallserial``, ``integer`` gives ``serial``, and ``biginteger`` gives
288288
``bigserial``.
289289

290+
For ``date`` columns:
291+
292+
======== ===========
293+
Option Description
294+
======== ===========
295+
default set default value (use with ``CURRENT_DATE``)
296+
======== ===========
297+
298+
For ``time`` columns:
299+
300+
======== ===========
301+
Option Description
302+
======== ===========
303+
default set default value (use with ``CURRENT_TIME``)
304+
timezone enable or disable the ``with time zone`` option *(only applies to Postgres)*
305+
======== ===========
306+
307+
For ``datetime`` columns:
308+
309+
======== ===========
310+
Option Description
311+
======== ===========
312+
default set default value (use with ``CURRENT_TIMESTAMP``)
313+
timezone enable or disable the ``with time zone`` option *(only applies to Postgres)*
314+
======== ===========
315+
290316
For ``timestamp`` columns:
291317

292318
======== ===========

src/Db/Adapter/AbstractAdapter.php

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,19 +1114,30 @@ public function castToBool($value): mixed
11141114
*/
11151115
protected function getDefaultValueDefinition(mixed $default, ?string $columnType = null): string
11161116
{
1117-
$datetimeTypes = [
1118-
static::TYPE_DATETIME,
1119-
static::TYPE_TIMESTAMP,
1120-
static::TYPE_TIME,
1121-
static::TYPE_DATE,
1117+
// SQL functions mapped to their valid column types (ordered longest-first to avoid prefix conflicts)
1118+
$sqlFunctionTypes = [
1119+
'CURRENT_TIMESTAMP' => [static::TYPE_DATETIME, static::TYPE_TIMESTAMP, static::TYPE_TIME, static::TYPE_DATE],
1120+
'CURRENT_DATE' => [static::TYPE_DATE],
1121+
'CURRENT_TIME' => [static::TYPE_TIME],
11221122
];
11231123

11241124
if ($default instanceof Literal) {
11251125
$default = (string)$default;
1126-
} elseif (is_string($default) && stripos($default, 'CURRENT_TIMESTAMP') === 0) {
1127-
// Only skip quoting CURRENT_TIMESTAMP for datetime-related column types.
1128-
// For other types (like string), it should be quoted as a literal string value.
1129-
if (!in_array($columnType, $datetimeTypes, true)) {
1126+
} elseif (is_string($default) && $columnType !== null) {
1127+
$matched = false;
1128+
foreach ($sqlFunctionTypes as $function => $validTypes) {
1129+
// Match function name at start, followed by end of string or opening parenthesis
1130+
$len = strlen($function);
1131+
if (
1132+
stripos($default, $function) === 0 &&
1133+
(strlen($default) === $len || $default[$len] === '(') &&
1134+
in_array($columnType, $validTypes, true)
1135+
) {
1136+
$matched = true;
1137+
break;
1138+
}
1139+
}
1140+
if (!$matched) {
11301141
$default = $this->quoteString($default);
11311142
}
11321143
} elseif (is_string($default)) {

tests/TestCase/Db/Adapter/AbstractAdapterTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,37 @@ public static function currentTimestampDefaultValueProvider(): array
161161
' DEFAULT CURRENT_TIMESTAMP(3)',
162162
],
163163

164+
// CURRENT_DATE on date type should NOT be quoted
165+
'CURRENT_DATE on date' => [
166+
'CURRENT_DATE',
167+
AbstractAdapter::TYPE_DATE,
168+
' DEFAULT CURRENT_DATE',
169+
],
170+
// CURRENT_DATE on non-date types SHOULD be quoted
171+
'CURRENT_DATE on datetime should be quoted' => [
172+
'CURRENT_DATE',
173+
AbstractAdapter::TYPE_DATETIME,
174+
" DEFAULT 'CURRENT_DATE'",
175+
],
176+
'CURRENT_DATE on string should be quoted' => [
177+
'CURRENT_DATE',
178+
AbstractAdapter::TYPE_STRING,
179+
" DEFAULT 'CURRENT_DATE'",
180+
],
181+
182+
// CURRENT_TIME on time type should NOT be quoted
183+
'CURRENT_TIME on time' => [
184+
'CURRENT_TIME',
185+
AbstractAdapter::TYPE_TIME,
186+
' DEFAULT CURRENT_TIME',
187+
],
188+
// CURRENT_TIME on non-time types SHOULD be quoted
189+
'CURRENT_TIME on datetime should be quoted' => [
190+
'CURRENT_TIME',
191+
AbstractAdapter::TYPE_DATETIME,
192+
" DEFAULT 'CURRENT_TIME'",
193+
],
194+
164195
// CURRENT_TIMESTAMP on non-datetime types SHOULD be quoted (bug #1891)
165196
'CURRENT_TIMESTAMP on string should be quoted' => [
166197
'CURRENT_TIMESTAMP',

0 commit comments

Comments
 (0)