diff --git a/docs/en/writing-migrations.rst b/docs/en/writing-migrations.rst index 8df520ec..a30b9cc9 100644 --- a/docs/en/writing-migrations.rst +++ b/docs/en/writing-migrations.rst @@ -287,6 +287,32 @@ appropriate for the integer size, so that ``smallinteger`` will give you ``smallserial``, ``integer`` gives ``serial``, and ``biginteger`` gives ``bigserial``. +For ``date`` columns: + +======== =========== +Option Description +======== =========== +default set default value (use with ``CURRENT_DATE``) +======== =========== + +For ``time`` columns: + +======== =========== +Option Description +======== =========== +default set default value (use with ``CURRENT_TIME``) +timezone enable or disable the ``with time zone`` option *(only applies to Postgres)* +======== =========== + +For ``datetime`` columns: + +======== =========== +Option Description +======== =========== +default set default value (use with ``CURRENT_TIMESTAMP``) +timezone enable or disable the ``with time zone`` option *(only applies to Postgres)* +======== =========== + For ``timestamp`` columns: ======== =========== diff --git a/src/Db/Adapter/AbstractAdapter.php b/src/Db/Adapter/AbstractAdapter.php index 7251ba31..e2e9c403 100644 --- a/src/Db/Adapter/AbstractAdapter.php +++ b/src/Db/Adapter/AbstractAdapter.php @@ -1114,19 +1114,30 @@ public function castToBool($value): mixed */ protected function getDefaultValueDefinition(mixed $default, ?string $columnType = null): string { - $datetimeTypes = [ - static::TYPE_DATETIME, - static::TYPE_TIMESTAMP, - static::TYPE_TIME, - static::TYPE_DATE, + // SQL functions mapped to their valid column types (ordered longest-first to avoid prefix conflicts) + $sqlFunctionTypes = [ + 'CURRENT_TIMESTAMP' => [static::TYPE_DATETIME, static::TYPE_TIMESTAMP, static::TYPE_TIME, static::TYPE_DATE], + 'CURRENT_DATE' => [static::TYPE_DATE], + 'CURRENT_TIME' => [static::TYPE_TIME], ]; if ($default instanceof Literal) { $default = (string)$default; - } elseif (is_string($default) && stripos($default, 'CURRENT_TIMESTAMP') === 0) { - // Only skip quoting CURRENT_TIMESTAMP for datetime-related column types. - // For other types (like string), it should be quoted as a literal string value. - if (!in_array($columnType, $datetimeTypes, true)) { + } elseif (is_string($default) && $columnType !== null) { + $matched = false; + foreach ($sqlFunctionTypes as $function => $validTypes) { + // Match function name at start, followed by end of string or opening parenthesis + $len = strlen($function); + if ( + stripos($default, $function) === 0 && + (strlen($default) === $len || $default[$len] === '(') && + in_array($columnType, $validTypes, true) + ) { + $matched = true; + break; + } + } + if (!$matched) { $default = $this->quoteString($default); } } elseif (is_string($default)) { diff --git a/tests/TestCase/Db/Adapter/AbstractAdapterTest.php b/tests/TestCase/Db/Adapter/AbstractAdapterTest.php index 74cdc9f2..3f66fff3 100644 --- a/tests/TestCase/Db/Adapter/AbstractAdapterTest.php +++ b/tests/TestCase/Db/Adapter/AbstractAdapterTest.php @@ -161,6 +161,37 @@ public static function currentTimestampDefaultValueProvider(): array ' DEFAULT CURRENT_TIMESTAMP(3)', ], + // CURRENT_DATE on date type should NOT be quoted + 'CURRENT_DATE on date' => [ + 'CURRENT_DATE', + AbstractAdapter::TYPE_DATE, + ' DEFAULT CURRENT_DATE', + ], + // CURRENT_DATE on non-date types SHOULD be quoted + 'CURRENT_DATE on datetime should be quoted' => [ + 'CURRENT_DATE', + AbstractAdapter::TYPE_DATETIME, + " DEFAULT 'CURRENT_DATE'", + ], + 'CURRENT_DATE on string should be quoted' => [ + 'CURRENT_DATE', + AbstractAdapter::TYPE_STRING, + " DEFAULT 'CURRENT_DATE'", + ], + + // CURRENT_TIME on time type should NOT be quoted + 'CURRENT_TIME on time' => [ + 'CURRENT_TIME', + AbstractAdapter::TYPE_TIME, + ' DEFAULT CURRENT_TIME', + ], + // CURRENT_TIME on non-time types SHOULD be quoted + 'CURRENT_TIME on datetime should be quoted' => [ + 'CURRENT_TIME', + AbstractAdapter::TYPE_DATETIME, + " DEFAULT 'CURRENT_TIME'", + ], + // CURRENT_TIMESTAMP on non-datetime types SHOULD be quoted (bug #1891) 'CURRENT_TIMESTAMP on string should be quoted' => [ 'CURRENT_TIMESTAMP',