diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 4ac1f10bd..b86dc431e 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -31,6 +31,8 @@ abstract class Adapter protected int $inTransaction = 0; + protected bool $alterLocks = false; + /** * @var array */ @@ -1434,4 +1436,25 @@ abstract public function setSupportForAttributes(bool $support): bool; */ abstract public function getSupportForIntegerBooleans(): bool; + /** + * Does the adapter have support for ALTER TABLE locking modes? + * + * When enabled, adapters can specify lock behavior (e.g., LOCK=SHARED) + * during ALTER TABLE operations to control concurrent access. + * + * @return bool + */ + abstract public function getSupportForAlterLocks(): bool; + + /** + * @param bool $enable + * + * @return $this + */ + public function enableAlterLocks(bool $enable): self + { + $this->alterLocks = $enable; + + return $this; + } } diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index a6233d189..0cc86e6c5 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -2220,4 +2220,9 @@ public function getSupportForOptionalSpatialAttributeWithExistingRows(): bool { return true; } + + public function getSupportForAlterLocks(): bool + { + return true; + } } diff --git a/src/Database/Adapter/Mongo.php b/src/Database/Adapter/Mongo.php index 1a7b8e29f..95c0a0fdc 100644 --- a/src/Database/Adapter/Mongo.php +++ b/src/Database/Adapter/Mongo.php @@ -3211,4 +3211,9 @@ public function getTenantQuery(string $collection, string $alias = ''): string { return ''; } + + public function getSupportForAlterLocks(): bool + { + return false; + } } diff --git a/src/Database/Adapter/Pool.php b/src/Database/Adapter/Pool.php index 2723a20db..537463ada 100644 --- a/src/Database/Adapter/Pool.php +++ b/src/Database/Adapter/Pool.php @@ -632,4 +632,9 @@ public function setAuthorization(Authorization $authorization): self $this->authorization = $authorization; return $this; } + + public function getSupportForAlterLocks(): bool + { + return $this->delegate(__FUNCTION__, \func_get_args()); + } } diff --git a/src/Database/Adapter/SQL.php b/src/Database/Adapter/SQL.php index 2ee1b1324..08ce3b63b 100644 --- a/src/Database/Adapter/SQL.php +++ b/src/Database/Adapter/SQL.php @@ -247,7 +247,7 @@ public function createAttribute(string $collection, string $id, string $type, in { $id = $this->quote($this->filter($id)); $type = $this->getSQLType($type, $size, $signed, $array, $required); - $sql = "ALTER TABLE {$this->getSQLTable($collection)} ADD COLUMN {$id} {$type};"; + $sql = "ALTER TABLE {$this->getSQLTable($collection)} ADD COLUMN {$id} {$type} {$this->getLockType()};"; $sql = $this->trigger(Database::EVENT_ATTRIBUTE_CREATE, $sql); try { @@ -284,7 +284,7 @@ public function createAttributes(string $collection, array $attributes): bool $columns = \implode(', ADD COLUMN ', $parts); - $sql = "ALTER TABLE {$this->getSQLTable($collection)} ADD COLUMN {$columns};"; + $sql = "ALTER TABLE {$this->getSQLTable($collection)} ADD COLUMN {$columns} {$this->getLockType()};"; $sql = $this->trigger(Database::EVENT_ATTRIBUTE_CREATE, $sql); try { @@ -3514,4 +3514,18 @@ public function setSupportForAttributes(bool $support): bool { return true; } + + public function getSupportForAlterLocks(): bool + { + return false; + } + + public function getLockType(): string + { + if ($this->getSupportForAlterLocks() && $this->alterLocks) { + return ',LOCK=SHARED'; + } + + return ''; + } } diff --git a/src/Database/Adapter/SQLite.php b/src/Database/Adapter/SQLite.php index e50bd2068..1260ccca0 100644 --- a/src/Database/Adapter/SQLite.php +++ b/src/Database/Adapter/SQLite.php @@ -1866,4 +1866,9 @@ public function getUpsertStatement( return $stmt; } + + public function getSupportForAlterLocks(): bool + { + return false; + } } diff --git a/src/Database/Database.php b/src/Database/Database.php index fa1718b54..557ab7f38 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -1218,6 +1218,23 @@ public function getTenantPerDocument(): bool return $this->adapter->getTenantPerDocument(); } + /** + * Enable or disable LOCK=SHARED during ALTER TABLE operation + * + * Set lock mode when altering tables + * + * @param bool $enabled + * @return static + */ + public function enableLocks(bool $enabled): static + { + if ($this->adapter->getSupportForAlterLocks()) { + $this->adapter->enableAlterLocks($enabled); + } + + return $this; + } + public function getPreserveDates(): bool { return $this->preserveDates; diff --git a/tests/e2e/Adapter/SharedTables/MariaDBTest.php b/tests/e2e/Adapter/SharedTables/MariaDBTest.php index 5205d8b6b..f6574ab0d 100644 --- a/tests/e2e/Adapter/SharedTables/MariaDBTest.php +++ b/tests/e2e/Adapter/SharedTables/MariaDBTest.php @@ -53,7 +53,9 @@ public function getDatabase(bool $fresh = false): Database ->setDatabase('utopiaTests') ->setSharedTables(true) ->setTenant(999) - ->setNamespace(static::$namespace = ''); + ->setNamespace(static::$namespace = '') + ->enableLocks(true) + ; if ($database->exists()) { $database->delete(); diff --git a/tests/e2e/Adapter/SharedTables/MySQLTest.php b/tests/e2e/Adapter/SharedTables/MySQLTest.php index 1824bfcc0..697c42c7e 100644 --- a/tests/e2e/Adapter/SharedTables/MySQLTest.php +++ b/tests/e2e/Adapter/SharedTables/MySQLTest.php @@ -55,7 +55,9 @@ public function getDatabase(): Database ->setDatabase('utopiaTests') ->setSharedTables(true) ->setTenant(999) - ->setNamespace(static::$namespace = ''); + ->setNamespace(static::$namespace = '') + ->enableLocks(true) + ; if ($database->exists()) { $database->delete();