Merge pull request #25091 from nextcloud/enhancement/ocp-db-exception-abstraction
Add our own DB exception abstraction
This commit is contained in:
commit
b9287f9780
|
@ -161,6 +161,7 @@ return array(
|
|||
'OCP\\Contacts\\ContactsMenu\\IProvider' => $baseDir . '/lib/public/Contacts/ContactsMenu/IProvider.php',
|
||||
'OCP\\Contacts\\Events\\ContactInteractedWithEvent' => $baseDir . '/lib/public/Contacts/Events/ContactInteractedWithEvent.php',
|
||||
'OCP\\Contacts\\IManager' => $baseDir . '/lib/public/Contacts/IManager.php',
|
||||
'OCP\\DB\\Exception' => $baseDir . '/lib/public/DB/Exception.php',
|
||||
'OCP\\DB\\IPreparedStatement' => $baseDir . '/lib/public/DB/IPreparedStatement.php',
|
||||
'OCP\\DB\\IResult' => $baseDir . '/lib/public/DB/IResult.php',
|
||||
'OCP\\DB\\ISchemaWrapper' => $baseDir . '/lib/public/DB/ISchemaWrapper.php',
|
||||
|
@ -953,6 +954,7 @@ return array(
|
|||
'OC\\DB\\Connection' => $baseDir . '/lib/private/DB/Connection.php',
|
||||
'OC\\DB\\ConnectionAdapter' => $baseDir . '/lib/private/DB/ConnectionAdapter.php',
|
||||
'OC\\DB\\ConnectionFactory' => $baseDir . '/lib/private/DB/ConnectionFactory.php',
|
||||
'OC\\DB\\Exceptions\\DbalException' => $baseDir . '/lib/private/DB/Exceptions/DbalException.php',
|
||||
'OC\\DB\\MDB2SchemaManager' => $baseDir . '/lib/private/DB/MDB2SchemaManager.php',
|
||||
'OC\\DB\\MDB2SchemaReader' => $baseDir . '/lib/private/DB/MDB2SchemaReader.php',
|
||||
'OC\\DB\\MigrationException' => $baseDir . '/lib/private/DB/MigrationException.php',
|
||||
|
|
|
@ -190,6 +190,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OCP\\Contacts\\ContactsMenu\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IProvider.php',
|
||||
'OCP\\Contacts\\Events\\ContactInteractedWithEvent' => __DIR__ . '/../../..' . '/lib/public/Contacts/Events/ContactInteractedWithEvent.php',
|
||||
'OCP\\Contacts\\IManager' => __DIR__ . '/../../..' . '/lib/public/Contacts/IManager.php',
|
||||
'OCP\\DB\\Exception' => __DIR__ . '/../../..' . '/lib/public/DB/Exception.php',
|
||||
'OCP\\DB\\IPreparedStatement' => __DIR__ . '/../../..' . '/lib/public/DB/IPreparedStatement.php',
|
||||
'OCP\\DB\\IResult' => __DIR__ . '/../../..' . '/lib/public/DB/IResult.php',
|
||||
'OCP\\DB\\ISchemaWrapper' => __DIR__ . '/../../..' . '/lib/public/DB/ISchemaWrapper.php',
|
||||
|
@ -982,6 +983,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OC\\DB\\Connection' => __DIR__ . '/../../..' . '/lib/private/DB/Connection.php',
|
||||
'OC\\DB\\ConnectionAdapter' => __DIR__ . '/../../..' . '/lib/private/DB/ConnectionAdapter.php',
|
||||
'OC\\DB\\ConnectionFactory' => __DIR__ . '/../../..' . '/lib/private/DB/ConnectionFactory.php',
|
||||
'OC\\DB\\Exceptions\\DbalException' => __DIR__ . '/../../..' . '/lib/private/DB/Exceptions/DbalException.php',
|
||||
'OC\\DB\\MDB2SchemaManager' => __DIR__ . '/../../..' . '/lib/private/DB/MDB2SchemaManager.php',
|
||||
'OC\\DB\\MDB2SchemaReader' => __DIR__ . '/../../..' . '/lib/private/DB/MDB2SchemaReader.php',
|
||||
'OC\\DB\\MigrationException' => __DIR__ . '/../../..' . '/lib/private/DB/MigrationException.php',
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
namespace OC\DB;
|
||||
|
||||
use Doctrine\DBAL\Exception;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
|
||||
/**
|
||||
|
@ -49,7 +50,9 @@ class Adapter {
|
|||
|
||||
/**
|
||||
* @param string $table name
|
||||
*
|
||||
* @return int id of last insert statement
|
||||
* @throws Exception
|
||||
*/
|
||||
public function lastInsertId($table) {
|
||||
return (int) $this->conn->realLastInsertId($table);
|
||||
|
@ -67,6 +70,7 @@ class Adapter {
|
|||
* Create an exclusive read+write lock on a table
|
||||
*
|
||||
* @param string $tableName
|
||||
* @throws Exception
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function lockTable($tableName) {
|
||||
|
@ -77,6 +81,7 @@ class Adapter {
|
|||
/**
|
||||
* Release a previous acquired lock again
|
||||
*
|
||||
* @throws Exception
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function unlockTable() {
|
||||
|
@ -94,7 +99,7 @@ class Adapter {
|
|||
* If this is null or an empty array, all keys of $input will be compared
|
||||
* Please note: text fields (clob) must not be used in the compare array
|
||||
* @return int number of inserted rows
|
||||
* @throws \Doctrine\DBAL\Exception
|
||||
* @throws Exception
|
||||
* @deprecated 15.0.0 - use unique index and "try { $db->insert() } catch (UniqueConstraintViolationException $e) {}" instead, because it is more reliable and does not have the risk for deadlocks - see https://github.com/nextcloud/server/pull/12371
|
||||
*/
|
||||
public function insertIfNotExist($table, $input, array $compare = null) {
|
||||
|
@ -130,6 +135,9 @@ class Adapter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \OCP\DB\Exception
|
||||
*/
|
||||
public function insertIgnoreConflict(string $table,array $values) : int {
|
||||
try {
|
||||
$builder = $this->conn->getQueryBuilder();
|
||||
|
|
|
@ -74,6 +74,9 @@ class Connection extends ReconnectWrapper {
|
|||
/** @var int */
|
||||
protected $queriesExecuted = 0;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function connect() {
|
||||
try {
|
||||
return parent::connect();
|
||||
|
@ -183,7 +186,9 @@ class Connection extends ReconnectWrapper {
|
|||
* @param string $statement The SQL statement to prepare.
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
*
|
||||
* @return Statement The prepared statement.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function prepare($statement, $limit = null, $offset = null): Statement {
|
||||
if ($limit === -1) {
|
||||
|
@ -221,6 +226,9 @@ class Connection extends ReconnectWrapper {
|
|||
return parent::executeQuery($sql, $params, $types, $qcp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function executeUpdate(string $sql, array $params = [], array $types = []): int {
|
||||
$sql = $this->replaceTablePrefix($sql);
|
||||
$sql = $this->adapter->fixupStatement($sql);
|
||||
|
@ -258,7 +266,9 @@ class Connection extends ReconnectWrapper {
|
|||
* columns or sequences.
|
||||
*
|
||||
* @param string $seqName Name of the sequence object from which the ID should be returned.
|
||||
*
|
||||
* @return string the last inserted ID.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function lastInsertId($seqName = null) {
|
||||
if ($seqName) {
|
||||
|
@ -267,7 +277,10 @@ class Connection extends ReconnectWrapper {
|
|||
return $this->adapter->lastInsertId($seqName);
|
||||
}
|
||||
|
||||
// internal use
|
||||
/**
|
||||
* @internal
|
||||
* @throws Exception
|
||||
*/
|
||||
public function realLastInsertId($seqName = null) {
|
||||
return parent::lastInsertId($seqName);
|
||||
}
|
||||
|
@ -364,7 +377,9 @@ class Connection extends ReconnectWrapper {
|
|||
* Create an exclusive read+write lock on a table
|
||||
*
|
||||
* @param string $tableName
|
||||
*
|
||||
* @throws \BadMethodCallException When trying to acquire a second lock
|
||||
* @throws Exception
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function lockTable($tableName) {
|
||||
|
@ -380,6 +395,7 @@ class Connection extends ReconnectWrapper {
|
|||
/**
|
||||
* Release a previous acquired lock again
|
||||
*
|
||||
* @throws Exception
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function unlockTable() {
|
||||
|
@ -415,6 +431,8 @@ class Connection extends ReconnectWrapper {
|
|||
* Drop a table from the database if it exists
|
||||
*
|
||||
* @param string $table table name without the prefix
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function dropTable($table) {
|
||||
$table = $this->tablePrefix . trim($table);
|
||||
|
@ -428,7 +446,9 @@ class Connection extends ReconnectWrapper {
|
|||
* Check if a table exists
|
||||
*
|
||||
* @param string $table table name without the prefix
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function tableExists($table) {
|
||||
$table = $this->tablePrefix . trim($table);
|
||||
|
@ -483,6 +503,7 @@ class Connection extends ReconnectWrapper {
|
|||
* Create the schema of the connected database
|
||||
*
|
||||
* @return Schema
|
||||
* @throws Exception
|
||||
*/
|
||||
public function createSchema() {
|
||||
$schemaManager = new MDB2SchemaManager($this);
|
||||
|
@ -494,6 +515,8 @@ class Connection extends ReconnectWrapper {
|
|||
* Migrate the database to the given schema
|
||||
*
|
||||
* @param Schema $toSchema
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function migrateToSchema(Schema $toSchema) {
|
||||
$schemaManager = new MDB2SchemaManager($this);
|
||||
|
|
|
@ -25,8 +25,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace OC\DB;
|
||||
|
||||
use Doctrine\DBAL\Exception;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use OC\DB\Exceptions\DbalException;
|
||||
use OCP\DB\IPreparedStatement;
|
||||
use OCP\DB\IResult;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
|
@ -49,51 +51,95 @@ class ConnectionAdapter implements IDBConnection {
|
|||
}
|
||||
|
||||
public function prepare($sql, $limit = null, $offset = null): IPreparedStatement {
|
||||
return new PreparedStatement(
|
||||
$this->inner->prepare($sql, $limit, $offset)
|
||||
);
|
||||
try {
|
||||
return new PreparedStatement(
|
||||
$this->inner->prepare($sql, $limit, $offset)
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function executeQuery(string $sql, array $params = [], $types = []): IResult {
|
||||
return new ResultAdapter(
|
||||
$this->inner->executeQuery($sql, $params, $types)
|
||||
);
|
||||
try {
|
||||
return new ResultAdapter(
|
||||
$this->inner->executeQuery($sql, $params, $types)
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function executeUpdate(string $sql, array $params = [], array $types = []): int {
|
||||
return $this->inner->executeUpdate($sql, $params, $types);
|
||||
try {
|
||||
return $this->inner->executeUpdate($sql, $params, $types);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function executeStatement($sql, array $params = [], array $types = []): int {
|
||||
return $this->inner->executeStatement($sql, $params, $types);
|
||||
try {
|
||||
return $this->inner->executeStatement($sql, $params, $types);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function lastInsertId(string $table): int {
|
||||
return (int) $this->inner->lastInsertId($table);
|
||||
try {
|
||||
return (int)$this->inner->lastInsertId($table);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function insertIfNotExist(string $table, array $input, array $compare = null) {
|
||||
return $this->inner->insertIfNotExist($table, $input, $compare);
|
||||
try {
|
||||
return $this->inner->insertIfNotExist($table, $input, $compare);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function insertIgnoreConflict(string $table, array $values): int {
|
||||
return $this->inner->insertIgnoreConflict($table, $values);
|
||||
try {
|
||||
return $this->inner->insertIgnoreConflict($table, $values);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []): int {
|
||||
return $this->inner->setValues($table, $keys, $values, $updatePreconditionValues);
|
||||
try {
|
||||
return $this->inner->setValues($table, $keys, $values, $updatePreconditionValues);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function lockTable($tableName): void {
|
||||
$this->inner->lockTable($tableName);
|
||||
try {
|
||||
$this->inner->lockTable($tableName);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function unlockTable(): void {
|
||||
$this->inner->unlockTable();
|
||||
try {
|
||||
$this->inner->unlockTable();
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function beginTransaction(): void {
|
||||
$this->inner->beginTransaction();
|
||||
try {
|
||||
$this->inner->beginTransaction();
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function inTransaction(): bool {
|
||||
|
@ -101,11 +147,19 @@ class ConnectionAdapter implements IDBConnection {
|
|||
}
|
||||
|
||||
public function commit(): void {
|
||||
$this->inner->commit();
|
||||
try {
|
||||
$this->inner->commit();
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function rollBack(): void {
|
||||
$this->inner->rollBack();
|
||||
try {
|
||||
$this->inner->rollBack();
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function getError(): string {
|
||||
|
@ -121,7 +175,11 @@ class ConnectionAdapter implements IDBConnection {
|
|||
}
|
||||
|
||||
public function connect(): bool {
|
||||
return $this->inner->connect();
|
||||
try {
|
||||
return $this->inner->connect();
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function close(): void {
|
||||
|
@ -140,11 +198,19 @@ class ConnectionAdapter implements IDBConnection {
|
|||
}
|
||||
|
||||
public function dropTable(string $table): void {
|
||||
$this->inner->dropTable($table);
|
||||
try {
|
||||
$this->inner->dropTable($table);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function tableExists(string $table): bool {
|
||||
return $this->inner->tableExists($table);
|
||||
try {
|
||||
return $this->inner->tableExists($table);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function escapeLikeParameter(string $param): string {
|
||||
|
@ -159,11 +225,19 @@ class ConnectionAdapter implements IDBConnection {
|
|||
* @todo leaks a 3rdparty type
|
||||
*/
|
||||
public function createSchema(): Schema {
|
||||
return $this->inner->createSchema();
|
||||
try {
|
||||
return $this->inner->createSchema();
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function migrateToSchema(Schema $toSchema): void {
|
||||
$this->inner->migrateToSchema($toSchema);
|
||||
try {
|
||||
$this->inner->migrateToSchema($toSchema);
|
||||
} catch (Exception $e) {
|
||||
throw DbalException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function getInner(): Connection {
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* @copyright 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OC\DB\Exceptions;
|
||||
|
||||
use Doctrine\DBAL\ConnectionException;
|
||||
use Doctrine\DBAL\Exception\ConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\DatabaseObjectExistsException;
|
||||
use Doctrine\DBAL\Exception\DatabaseObjectNotFoundException;
|
||||
use Doctrine\DBAL\Exception\DeadlockException;
|
||||
use Doctrine\DBAL\Exception\DriverException;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\InvalidArgumentException;
|
||||
use Doctrine\DBAL\Exception\InvalidFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NonUniqueFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NotNullConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\ServerException;
|
||||
use Doctrine\DBAL\Exception\SyntaxErrorException;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
use OCP\DB\Exception;
|
||||
|
||||
/**
|
||||
* Wrapper around the raw dbal exception, so we can pass it to apps that catch
|
||||
* our OCP db exception
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
class DbalException extends Exception {
|
||||
|
||||
/** @var \Doctrine\DBAL\Exception */
|
||||
private $original;
|
||||
|
||||
/**
|
||||
* @param \Doctrine\DBAL\Exception $original
|
||||
* @param int $code
|
||||
* @param string $message
|
||||
*/
|
||||
private function __construct(\Doctrine\DBAL\Exception $original, int $code, string $message) {
|
||||
parent::__construct(
|
||||
$message,
|
||||
$code,
|
||||
$original
|
||||
);
|
||||
$this->original = $original;
|
||||
}
|
||||
|
||||
public static function wrap(\Doctrine\DBAL\Exception $original, string $message = ''): self {
|
||||
return new self(
|
||||
$original,
|
||||
is_int($original->getCode()) ? $original->getCode() : 0,
|
||||
empty($message) ? $original->getMessage() : $message
|
||||
);
|
||||
}
|
||||
|
||||
public function getReason(): ?int {
|
||||
/**
|
||||
* Generic errors
|
||||
*/
|
||||
if ($this->original instanceof ConnectionException) {
|
||||
return parent::REASON_CONNECTION_LOST;
|
||||
}
|
||||
if ($this->original instanceof DriverException) {
|
||||
return parent::REASON_DRIVER;
|
||||
}
|
||||
if ($this->original instanceof InvalidArgumentException) {
|
||||
return parent::REASON_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constraint errors
|
||||
*/
|
||||
if ($this->original instanceof ForeignKeyConstraintViolationException) {
|
||||
return parent::REASON_FOREIGN_KEY_VIOLATION;
|
||||
}
|
||||
if ($this->original instanceof NotNullConstraintViolationException) {
|
||||
return parent::REASON_NOT_NULL_CONSTRAINT_VIOLATION;
|
||||
}
|
||||
if ($this->original instanceof UniqueConstraintViolationException) {
|
||||
return parent::REASON_UNIQUE_CONSTRAINT_VIOLATION;
|
||||
}
|
||||
// The base exception comes last
|
||||
if ($this->original instanceof ConstraintViolationException) {
|
||||
return parent::REASON_CONSTRAINT_VIOLATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Other server errors
|
||||
*/
|
||||
if ($this->original instanceof DatabaseObjectExistsException) {
|
||||
return parent::REASON_DATABASE_OBJECT_EXISTS;
|
||||
}
|
||||
if ($this->original instanceof DatabaseObjectNotFoundException) {
|
||||
return parent::REASON_DATABASE_OBJECT_NOT_FOUND;
|
||||
}
|
||||
if ($this->original instanceof DeadlockException) {
|
||||
return parent::REASON_DEADLOCK;
|
||||
}
|
||||
if ($this->original instanceof InvalidFieldNameException) {
|
||||
return parent::REASON_INVALID_FIELD_NAME;
|
||||
}
|
||||
if ($this->original instanceof NonUniqueFieldNameException) {
|
||||
return parent::REASON_NON_UNIQUE_FIELD_NAME;
|
||||
}
|
||||
if ($this->original instanceof SyntaxErrorException) {
|
||||
return parent::REASON_SYNTAX_ERROR;
|
||||
}
|
||||
// The base server exception class comes last
|
||||
if ($this->original instanceof ServerException) {
|
||||
return parent::REASON_SERVER;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -82,6 +82,8 @@ class Migrator {
|
|||
|
||||
/**
|
||||
* @param \Doctrine\DBAL\Schema\Schema $targetSchema
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function migrate(Schema $targetSchema) {
|
||||
$this->noEmit = true;
|
||||
|
@ -171,6 +173,9 @@ class Migrator {
|
|||
return new Table($newName, $table->getColumns(), $newIndexes, [], [], $table->getOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function createSchema() {
|
||||
$this->connection->getConfiguration()->setSchemaAssetsFilter(function ($asset) {
|
||||
/** @var string|AbstractAsset $asset */
|
||||
|
@ -231,6 +236,8 @@ class Migrator {
|
|||
/**
|
||||
* @param \Doctrine\DBAL\Schema\Schema $targetSchema
|
||||
* @param \Doctrine\DBAL\Connection $connection
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function applySchema(Schema $targetSchema, \Doctrine\DBAL\Connection $connection = null) {
|
||||
if (is_null($connection)) {
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* @copyright 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2021 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCP\DB;
|
||||
|
||||
use Exception as BaseException;
|
||||
|
||||
/**
|
||||
* Database exception
|
||||
*
|
||||
* Thrown by Nextcloud's database abstraction layer. This is the base class that
|
||||
* any specific exception will extend. Use this class in your try-catch to catch
|
||||
* *any* error related to the database. Use any of the subclasses in the same
|
||||
* namespace if you are only interested in specific errors.
|
||||
*
|
||||
* @psalm-immutable
|
||||
* @since 21.0.0
|
||||
*/
|
||||
class Exception extends BaseException {
|
||||
|
||||
/**
|
||||
* Nextcloud lost connection to the database
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_CONNECTION_LOST = 1;
|
||||
|
||||
/**
|
||||
* A database constraint was violated
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_CONSTRAINT_VIOLATION = 2;
|
||||
|
||||
/**
|
||||
* A database object (table, column, index) already exists
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_DATABASE_OBJECT_EXISTS = 3;
|
||||
|
||||
/**
|
||||
* A database object (table, column, index) can't be found
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_DATABASE_OBJECT_NOT_FOUND = 4;
|
||||
|
||||
/**
|
||||
* The database ran into a deadlock
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_DEADLOCK = 5;
|
||||
|
||||
/**
|
||||
* The database driver encountered an issue
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_DRIVER = 6;
|
||||
|
||||
/**
|
||||
* A foreign key constraint was violated
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_FOREIGN_KEY_VIOLATION = 7;
|
||||
|
||||
/**
|
||||
* An invalid argument was passed to the database abstraction
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_INVALID_ARGUMENT = 8;
|
||||
|
||||
/**
|
||||
* A field name was invalid
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_INVALID_FIELD_NAME = 9;
|
||||
|
||||
/**
|
||||
* A name in the query was ambiguous
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_NON_UNIQUE_FIELD_NAME = 10;
|
||||
|
||||
/**
|
||||
* A not null contraint was violated
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_NOT_NULL_CONSTRAINT_VIOLATION = 11;
|
||||
|
||||
/**
|
||||
* A generic server error was encountered
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_SERVER = 12;
|
||||
|
||||
/**
|
||||
* A syntax error was reported by the server
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_SYNTAX_ERROR = 13;
|
||||
|
||||
/**
|
||||
* A unique constraint was violated
|
||||
*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const REASON_UNIQUE_CONSTRAINT_VIOLATION = 14;
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
* @psalm-return Exception::REASON_*
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public function getReason(): ?int {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@
|
|||
namespace OCP\DB\QueryBuilder;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use OCP\DB\Exception;
|
||||
use OCP\DB\IResult;
|
||||
|
||||
/**
|
||||
|
@ -154,6 +155,7 @@ interface IQueryBuilder {
|
|||
* to bridge old code to the new API
|
||||
*
|
||||
* @return IResult|int
|
||||
* @throws Exception since 21.0.0
|
||||
* @since 8.2.0
|
||||
*/
|
||||
public function execute();
|
||||
|
|
|
@ -39,8 +39,8 @@
|
|||
|
||||
namespace OCP;
|
||||
|
||||
use Doctrine\DBAL\Exception;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use OCP\DB\Exception;
|
||||
use OCP\DB\IPreparedStatement;
|
||||
use OCP\DB\IResult;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
|
@ -103,6 +103,7 @@ interface IDBConnection {
|
|||
* @param array $types The parameter types.
|
||||
* @return int The number of affected rows.
|
||||
* @since 8.0.0
|
||||
* @throws Exception since 21.0.0
|
||||
*
|
||||
* @deprecated 21.0.0 use executeStatement
|
||||
*/
|
||||
|
@ -119,6 +120,7 @@ interface IDBConnection {
|
|||
* @param array $types The parameter types.
|
||||
* @return int The number of affected rows.
|
||||
* @since 21.0.0
|
||||
* @throws Exception since 21.0.0
|
||||
*/
|
||||
public function executeStatement($sql, array $params = [], array $types = []): int;
|
||||
|
||||
|
@ -143,7 +145,7 @@ interface IDBConnection {
|
|||
* If this is null or an empty array, all keys of $input will be compared
|
||||
* Please note: text fields (clob) must not be used in the compare array
|
||||
* @return int number of inserted rows
|
||||
* @throws Exception
|
||||
* @throws Exception used to be the removed dbal exception, since 21.0.0 it's \OCP\DB\Exception
|
||||
* @since 6.0.0 - parameter $compare was added in 8.1.0, return type changed from boolean in 8.1.0
|
||||
* @deprecated 15.0.0 - use unique index and "try { $db->insert() } catch (UniqueConstraintViolationException $e) {}" instead, because it is more reliable and does not have the risk for deadlocks - see https://github.com/nextcloud/server/pull/12371
|
||||
*/
|
||||
|
@ -171,7 +173,7 @@ interface IDBConnection {
|
|||
* @param array $values (column name => value)
|
||||
* @param array $updatePreconditionValues ensure values match preconditions (column name => value)
|
||||
* @return int number of new rows
|
||||
* @throws Exception
|
||||
* @throws Exception used to be the removed dbal exception, since 21.0.0 it's \OCP\DB\Exception
|
||||
* @throws PreconditionNotMetException
|
||||
* @since 9.0.0
|
||||
*/
|
||||
|
@ -185,6 +187,7 @@ interface IDBConnection {
|
|||
* transaction while holding a lock.
|
||||
*
|
||||
* @param string $tableName
|
||||
* @throws Exception since 21.0.0
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function lockTable($tableName): void;
|
||||
|
@ -192,6 +195,7 @@ interface IDBConnection {
|
|||
/**
|
||||
* Release a previous acquired lock again
|
||||
*
|
||||
* @throws Exception since 21.0.0
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function unlockTable(): void;
|
||||
|
@ -255,6 +259,7 @@ interface IDBConnection {
|
|||
* Establishes the connection with the database.
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception since 21.0.0
|
||||
* @since 8.0.0
|
||||
*/
|
||||
public function connect(): bool;
|
||||
|
@ -288,6 +293,7 @@ interface IDBConnection {
|
|||
* Drop a table from the database if it exists
|
||||
*
|
||||
* @param string $table table name without the prefix
|
||||
* @throws Exception since 21.0.0
|
||||
* @since 8.0.0
|
||||
*/
|
||||
public function dropTable(string $table): void;
|
||||
|
@ -297,6 +303,7 @@ interface IDBConnection {
|
|||
*
|
||||
* @param string $table table name without the prefix
|
||||
* @return bool
|
||||
* @throws Exception since 21.0.0
|
||||
* @since 8.0.0
|
||||
*/
|
||||
public function tableExists(string $table): bool;
|
||||
|
@ -322,6 +329,7 @@ interface IDBConnection {
|
|||
* Create the schema of the connected database
|
||||
*
|
||||
* @return Schema
|
||||
* @throws Exception since 21.0.0
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function createSchema(): Schema;
|
||||
|
@ -330,6 +338,7 @@ interface IDBConnection {
|
|||
* Migrate the database to the given schema
|
||||
*
|
||||
* @param Schema $toSchema
|
||||
* @throws Exception since 21.0.0
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function migrateToSchema(Schema $toSchema): void;
|
||||
|
|
Loading…
Reference in New Issue