Skip to content

Commit

Permalink
Throw duplicate properly, create collections in transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
abnegate committed Aug 12, 2024
1 parent 7bc4146 commit 9a476e8
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 31 deletions.
68 changes: 40 additions & 28 deletions src/Database/Adapter/MariaDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -142,64 +142,73 @@ 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),
KEY _updated_at (_tenant, _updatedAt),
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,
_document VARCHAR(255) NOT NULL,
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;
Expand Down Expand Up @@ -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;
Expand Down
11 changes: 8 additions & 3 deletions src/Database/Adapter/MySQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 9a476e8

Please sign in to comment.