From 0bbc616c74daefd97eb564db0edf672aeea34f92 Mon Sep 17 00:00:00 2001 From: Benjamin Gaussorgues Date: Mon, 19 Oct 2026 16:30:50 +0200 Subject: [PATCH] feat(db): add smaller DBAL types when supported by database Signed-off-by: Benjamin Gaussorgues --- lib/composer/composer/autoload_classmap.php | 2 ++ lib/composer/composer/autoload_static.php | 2 ++ lib/private/DB/MigrationService.php | 11 ++++++ .../DB/Types/TimestampImmutableType.php | 35 +++++++++++++++++++ lib/private/DB/Types/TinyIntType.php | 32 +++++++++++++++++ lib/public/AppFramework/Db/Entity.php | 12 +++---- lib/public/AppFramework/ORM/Repository.php | 4 +-- lib/public/DB/Schema/ColumnType.php | 16 +++++++++ 8 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 lib/private/DB/Types/TimestampImmutableType.php create mode 100644 lib/private/DB/Types/TinyIntType.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 4467e4e6179c2..f59ac03d74ba0 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -1849,6 +1849,8 @@ 'OC\\DB\\Schema\\Index' => $baseDir . '/lib/private/DB/Schema/Index.php', 'OC\\DB\\Schema\\Table' => $baseDir . '/lib/private/DB/Schema/Table.php', 'OC\\DB\\SetTransactionIsolationLevel' => $baseDir . '/lib/private/DB/SetTransactionIsolationLevel.php', + 'OC\\DB\\Types\\TimestampImmutableType' => $baseDir . '/lib/private/DB/Types/TimestampImmutableType.php', + 'OC\\DB\\Types\\TinyIntType' => $baseDir . '/lib/private/DB/Types/TinyIntType.php', 'OC\\Dashboard\\Manager' => $baseDir . '/lib/private/Dashboard/Manager.php', 'OC\\DatabaseException' => $baseDir . '/lib/private/DatabaseException.php', 'OC\\DatabaseSetupException' => $baseDir . '/lib/private/DatabaseSetupException.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index dac59af04087a..05c5fc681930b 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -1890,6 +1890,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\DB\\Schema\\Index' => __DIR__ . '/../../..' . '/lib/private/DB/Schema/Index.php', 'OC\\DB\\Schema\\Table' => __DIR__ . '/../../..' . '/lib/private/DB/Schema/Table.php', 'OC\\DB\\SetTransactionIsolationLevel' => __DIR__ . '/../../..' . '/lib/private/DB/SetTransactionIsolationLevel.php', + 'OC\\DB\\Types\\TimestampImmutableType' => __DIR__ . '/../../..' . '/lib/private/DB/Types/TimestampImmutableType.php', + 'OC\\DB\\Types\\TinyIntType' => __DIR__ . '/../../..' . '/lib/private/DB/Types/TinyIntType.php', 'OC\\Dashboard\\Manager' => __DIR__ . '/../../..' . '/lib/private/Dashboard/Manager.php', 'OC\\DatabaseException' => __DIR__ . '/../../..' . '/lib/private/DatabaseException.php', 'OC\\DatabaseSetupException' => __DIR__ . '/../../..' . '/lib/private/DatabaseSetupException.php', diff --git a/lib/private/DB/MigrationService.php b/lib/private/DB/MigrationService.php index 31de44ac42eb7..dbb12170092af 100644 --- a/lib/private/DB/MigrationService.php +++ b/lib/private/DB/MigrationService.php @@ -14,9 +14,12 @@ use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Type; use OC\App\InfoParser; +use OC\DB\Types\TimestampImmutableType; +use OC\DB\Types\TinyIntType; use OC\Migration\SimpleOutput; use OCP\App\IAppManager; use OCP\DB\ISchemaWrapper; +use OCP\DB\Schema\ColumnType; use OCP\DB\Schema\SchemaException; use OCP\DB\Types; use OCP\IConfig; @@ -56,6 +59,14 @@ public function __construct( $this->output = $output; } + // Set custom Nextcloud types + if (!Type::hasType(ColumnType::TinyInt->value)) { + Type::addType(ColumnType::TinyInt->value, TinyIntType::class); + } + if (!Type::hasType(ColumnType::TimestampImmutable->value)) { + Type::addType(ColumnType::TimestampImmutable->value, TimestampImmutableType::class); + } + if ($this->appName === 'core') { $this->migrationsPath = \OC::$SERVERROOT . '/core/Migrations'; $this->migrationsNamespace = 'OC\\Core\\Migrations'; diff --git a/lib/private/DB/Types/TimestampImmutableType.php b/lib/private/DB/Types/TimestampImmutableType.php new file mode 100644 index 0000000000000..a2346ee51467e --- /dev/null +++ b/lib/private/DB/Types/TimestampImmutableType.php @@ -0,0 +1,35 @@ +value; + } + + #[Override] + public function getSQLDeclaration(array $column, AbstractPlatform $platform): string { + $declaration = parent::getSQLDeclaration($column, $platform); + + if ($platform instanceof MySQLPlatform || $platform instanceof MariaDBPlatform) { + $field = $column['notnull'] ?? true ? 'TIMESTAMP' : 'TIMESTAMP NULL'; + $declaration = str_replace('DATETIME', $field, $declaration); + } + return $declaration; + } +} diff --git a/lib/private/DB/Types/TinyIntType.php b/lib/private/DB/Types/TinyIntType.php new file mode 100644 index 0000000000000..e957c88c1c438 --- /dev/null +++ b/lib/private/DB/Types/TinyIntType.php @@ -0,0 +1,32 @@ +value; + } + + #[Override] + public function getSQLDeclaration(array $column, AbstractPlatform $platform): string { + $declaration = parent::getSQLDeclaration($column, $platform); + return $platform instanceof MySQLPlatform || $platform instanceof MariaDBPlatform + ? str_replace('SMALLINT', 'TINYINT', $declaration) + : $declaration; + } +} diff --git a/lib/public/AppFramework/Db/Entity.php b/lib/public/AppFramework/Db/Entity.php index d49150ae2a440..d56789b3c2ed0 100644 --- a/lib/public/AppFramework/Db/Entity.php +++ b/lib/public/AppFramework/Db/Entity.php @@ -63,7 +63,7 @@ public static function fromRow(array $row): static { } /** - * @return array with attribute and type + * @return array with attribute and type * @since 7.0.0 */ public function getFieldTypes(): array { @@ -143,7 +143,6 @@ protected function setter(string $name, array $args): void { } } $this->$name = $args[0]; - } /** @@ -155,8 +154,7 @@ protected function getter(string $name): mixed { if (property_exists($this, $name)) { return $this->$name; } else { - throw new \BadFunctionCallException($name - . ' is not a valid attribute'); + throw new \BadFunctionCallException($name . ' is not a valid attribute'); } } @@ -175,8 +173,7 @@ public function __call(string $methodName, array $args) { } elseif ($this->isGetterForBoolProperty($methodName)) { return $this->getter(lcfirst(substr($methodName, 2))); } else { - throw new \BadFunctionCallException($methodName - . ' does not exist'); + throw new \BadFunctionCallException($methodName . ' does not exist'); } } @@ -272,8 +269,7 @@ protected function addType(string $fieldName, string|ColumnType $type): void { 'int' => ColumnType::Integer, 'bool' => ColumnType::Boolean, 'double' => ColumnType::Float, - 'array', - 'object' => ColumnType::String, + 'array', 'object' => ColumnType::String, }; } diff --git a/lib/public/AppFramework/ORM/Repository.php b/lib/public/AppFramework/ORM/Repository.php index 7f3e26748b5c7..25842a9fa309d 100644 --- a/lib/public/AppFramework/ORM/Repository.php +++ b/lib/public/AppFramework/ORM/Repository.php @@ -95,14 +95,14 @@ private function hydrateRow(string $entityClass, mixed $row): object { /** @psalm-suppress MixedAssignment $value is a raw DB driver value; each branch below settype()s or reconstructs it. */ $value = match ($type) { - ColumnType::Bigint, ColumnType::Smallint, ColumnType::Integer => (int)$value, + ColumnType::Bigint, ColumnType::Smallint, ColumnType::Integer, ColumnType::TinyInt => (int)$value, ColumnType::Float => (float)$value, ColumnType::Boolean => (bool)$value, ColumnType::Binary, ColumnType::Decimal, ColumnType::Guid, ColumnType::Text, ColumnType::String => (string)$value, ColumnType::Time, ColumnType::Date, ColumnType::Datetime, ColumnType::DatetimeTz => $value instanceof \DateTime ? $value : new \DateTime((string)$value), - ColumnType::TimeImmutable, ColumnType::DateImmutable, ColumnType::DatetimeImmutable, ColumnType::DatetimeTzImmutable => $value instanceof \DateTimeImmutable + ColumnType::TimeImmutable, ColumnType::DateImmutable, ColumnType::DatetimeImmutable, ColumnType::DatetimeTzImmutable, ColumnType::TimestampImmutable => $value instanceof \DateTimeImmutable ? $value : new \DateTimeImmutable((string)$value), ColumnType::Json => is_array($value) ? $value : json_decode((string)$value, true), diff --git a/lib/public/DB/Schema/ColumnType.php b/lib/public/DB/Schema/ColumnType.php index 496157de59137..3845e79be55dc 100644 --- a/lib/public/DB/Schema/ColumnType.php +++ b/lib/public/DB/Schema/ColumnType.php @@ -173,6 +173,22 @@ enum ColumnType: string { */ case Guid = 'guid'; + /** + * Tiny int + * It is recommended for small values like status + * + * @since 36.0.0 + */ + case TinyInt = 'tinyint'; + + /** + * Unix timestamp returned as DateTimeImmutable + * It is recommended for dates that fits into a timestamp + * + * @since 36.0.0 + */ + case TimestampImmutable = 'timestamp_immutable'; + /** * @since 35.0.0 */