diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index 3b4b6d6c8..afb00379a 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -129,7 +129,7 @@ public function createCollection(string $name, array $attributes = [], array $in $indexStrings[$key] = "{$indexType} `{$indexId}` ({$indexAttributes}),"; } - $sql = " + $collectionStmt = " CREATE TABLE {$this->getSQLTable($id)} ( _id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, _uid VARCHAR(255) NOT NULL, @@ -142,7 +142,7 @@ public function createCollection(string $name, array $attributes = [], array $in "; if ($this->sharedTables) { - $sql .= " + $collectionStmt .= " _tenant INT(11) UNSIGNED DEFAULT NULL, UNIQUE KEY _uid (_tenant, _uid), KEY _created_at (_tenant, _createdAt), @@ -150,24 +150,18 @@ public function createCollection(string $name, array $attributes = [], array $in KEY _tenant_id (_tenant, _id) "; } else { - $sql .= " + $collectionStmt .= " UNIQUE KEY _uid (_uid), KEY _created_at (_createdAt), KEY _updated_at (_updatedAt) "; } - $sql .= ")"; - - $sql = $this->trigger(Database::EVENT_COLLECTION_CREATE, $sql); + $collectionStmt .= ")"; + $collectionStmt = $this->trigger(Database::EVENT_COLLECTION_CREATE, $collectionStmt); - try { - $this->getPDO() - ->prepare($sql) - ->execute(); - - $sql = " - CREATE TABLE IF NOT EXISTS {$this->getSQLTable($id . '_perms')} ( + $permissionsStmt = " + CREATE TABLE {$this->getSQLTable($id . '_perms')} ( _id int(11) UNSIGNED NOT NULL AUTO_INCREMENT, _type VARCHAR(12) NOT NULL, _permission VARCHAR(255) NOT NULL, @@ -175,31 +169,46 @@ public function createCollection(string $name, array $attributes = [], array $in PRIMARY KEY (_id), "; - if ($this->sharedTables) { - $sql .= " + if ($this->sharedTables) { + $permissionsStmt .= " _tenant INT(11) UNSIGNED DEFAULT NULL, UNIQUE INDEX _index1 (_document, _tenant, _type, _permission), INDEX _permission (_tenant, _permission, _type) "; - } else { - $sql .= " + } else { + $permissionsStmt .= " UNIQUE INDEX _index1 (_document, _type, _permission), INDEX _permission (_permission, _type) "; - } + } - $sql .= ")"; + $permissionsStmt .= ")"; + $permissionsStmt = $this->trigger(Database::EVENT_COLLECTION_CREATE, $permissionsStmt); - $sql = $this->trigger(Database::EVENT_COLLECTION_CREATE, $sql); + try { + $this->pdo->beginTransaction(); $this->getPDO() - ->prepare($sql) + ->prepare($collectionStmt) ->execute(); - } catch (\Exception $th) { + $this->getPDO() - ->prepare("DROP TABLE IF EXISTS {$this->getSQLTable($id)}, {$this->getSQLTable($id . '_perms')};") + ->prepare($permissionsStmt) ->execute(); - throw $th; + + if (!$this->pdo->commit()) { + throw new DatabaseException('Failed to commit transaction'); + } + } catch (\Exception $e) { + if (!$this->pdo->inTransaction()) { + $this->pdo->rollBack(); + } + + if ($e instanceof PDOException) { + $this->processException($e); + } + + throw $e; } return true; @@ -2246,17 +2255,20 @@ public function setTimeout(int $milliseconds, string $event = Database::EVENT_AL /** * @param PDOException $e * @throws TimeoutException + * @throws DuplicateException */ protected function processException(PDOException $e): void { - // Regular PDO if ($e->getCode() === '70100' && isset($e->errorInfo[1]) && $e->errorInfo[1] === 1969) { throw new TimeoutException($e->getMessage(), $e->getCode(), $e); + } else if ($e->getCode() === 1969 && isset($e->errorInfo[0]) && $e->errorInfo[0] === '70100') { + throw new TimeoutException($e->getMessage(), $e->getCode(), $e); } - // PDOProxy switches errorInfo PDOProxy.php line 64 - if ($e->getCode() === 1969 && isset($e->errorInfo[0]) && $e->errorInfo[0] === '70100') { - throw new TimeoutException($e->getMessage(), $e->getCode(), $e); + if ($e->getCode() === '42S01' && isset($e->errorInfo[1]) && $e->errorInfo[1] === 1050) { + throw new DuplicateException($e->getMessage(), $e->getCode(), $e); + } else if ($e->getCode() === 1050 && isset($e->errorInfo[0]) && $e->errorInfo[0] === '42S01') { + throw new DuplicateException($e->getMessage(), $e->getCode(), $e); } throw $e; diff --git a/src/Database/Adapter/MySQL.php b/src/Database/Adapter/MySQL.php index 287680390..40ee49d01 100644 --- a/src/Database/Adapter/MySQL.php +++ b/src/Database/Adapter/MySQL.php @@ -5,6 +5,7 @@ use PDOException; use Utopia\Database\Database; use Utopia\Database\Exception as DatabaseException; +use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Timeout as TimeoutException; class MySQL extends MariaDB @@ -37,16 +38,20 @@ public function setTimeout(int $milliseconds, string $event = Database::EVENT_AL /** * @param PDOException $e * @throws TimeoutException + * @throws DuplicateException */ protected function processException(PDOException $e): void { if ($e->getCode() === 'HY000' && isset($e->errorInfo[1]) && $e->errorInfo[1] === 3024) { throw new TimeoutException($e->getMessage(), $e->getCode(), $e); + } elseif ($e->getCode() === 3024 && isset($e->errorInfo[0]) && $e->errorInfo[0] === "HY000") { + throw new TimeoutException($e->getMessage(), $e->getCode(), $e); } - // PDOProxy which who switches errorInfo - if ($e->getCode() === 3024 && isset($e->errorInfo[0]) && $e->errorInfo[0] === "HY000") { - throw new TimeoutException($e->getMessage(), $e->getCode(), $e); + if ($e->getCode() === '42S01' && isset($e->errorInfo[1]) && $e->errorInfo[1] === 1050) { + throw new DuplicateException($e->getMessage(), $e->getCode(), $e); + } else if ($e->getCode() === 1050 && isset($e->errorInfo[0]) && $e->errorInfo[0] === '42S01') { + throw new DuplicateException($e->getMessage(), $e->getCode(), $e); } throw $e;