Add a method to lock a table
This commit is contained in:
parent
59a85a4c76
commit
7e3ce83526
|
@ -29,6 +29,7 @@ namespace OC\AppFramework\Db;
|
|||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDb;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\PreConditionNotMetException;
|
||||
|
||||
/**
|
||||
* @deprecated use IDBConnection directly, will be removed in ownCloud 10
|
||||
|
@ -157,12 +158,26 @@ class Db implements IDb {
|
|||
* @param array $updatePreconditionValues ensure values match preconditions (column name => value)
|
||||
* @return int number of new rows
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
* @throws PreconditionNotMetException
|
||||
* @throws PreConditionNotMetException
|
||||
*/
|
||||
public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
|
||||
return $this->connection->setValues($table, $keys, $values, $updatePreconditionValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function lockTable($tableName) {
|
||||
$this->connection->lockTable($tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function unlockTable() {
|
||||
$this->connection->unlockTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a transaction
|
||||
*/
|
||||
|
|
|
@ -57,6 +57,26 @@ class Adapter {
|
|||
return $statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an exclusive read+write lock on a table
|
||||
*
|
||||
* @param string $tableName
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function lockTable($tableName) {
|
||||
$this->conn->beginTransaction();
|
||||
$this->conn->executeUpdate('LOCK TABLE `' .$tableName . '` IN EXCLUSIVE MODE');
|
||||
}
|
||||
|
||||
/**
|
||||
* Release a previous acquired lock again
|
||||
*
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function unlockTable() {
|
||||
$this->conn->commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a row if the matching row does not exists.
|
||||
*
|
||||
|
|
|
@ -24,6 +24,18 @@
|
|||
namespace OC\DB;
|
||||
|
||||
class AdapterMySQL extends Adapter {
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
*/
|
||||
public function lockTable($tableName) {
|
||||
$this->conn->executeUpdate('LOCK TABLES `' .$tableName . '` WRITE');
|
||||
}
|
||||
|
||||
public function unlockTable() {
|
||||
$this->conn->executeUpdate('UNLOCK TABLES');
|
||||
}
|
||||
|
||||
public function fixupStatement($statement) {
|
||||
$statement = str_replace(' ILIKE ', ' COLLATE utf8_general_ci LIKE ', $statement);
|
||||
return $statement;
|
||||
|
|
|
@ -27,6 +27,18 @@
|
|||
namespace OC\DB;
|
||||
|
||||
class AdapterSqlite extends Adapter {
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
*/
|
||||
public function lockTable($tableName) {
|
||||
$this->conn->executeUpdate('BEGIN EXCLUSIVE TRANSACTION');
|
||||
}
|
||||
|
||||
public function unlockTable() {
|
||||
$this->conn->executeUpdate('COMMIT TRANSACTION');
|
||||
}
|
||||
|
||||
public function fixupStatement($statement) {
|
||||
$statement = preg_replace('( I?LIKE \?)', '$0 ESCAPE \'\\\'', $statement);
|
||||
$statement = preg_replace('/`(\w+)` ILIKE \?/', 'LOWER($1) LIKE LOWER(?)', $statement);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
*/
|
||||
|
||||
namespace OC\DB;
|
||||
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Configuration;
|
||||
|
@ -46,6 +47,8 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
|
|||
*/
|
||||
protected $adapter;
|
||||
|
||||
protected $lockedTable = null;
|
||||
|
||||
public function connect() {
|
||||
try {
|
||||
return parent::connect();
|
||||
|
@ -281,7 +284,7 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
|
|||
foreach ($values as $name => $value) {
|
||||
$updateQb->set($name, $updateQb->createNamedParameter($value, $this->getType($value)));
|
||||
}
|
||||
$where = $updateQb->expr()->andx();
|
||||
$where = $updateQb->expr()->andX();
|
||||
$whereValues = array_merge($keys, $updatePreconditionValues);
|
||||
foreach ($whereValues as $name => $value) {
|
||||
$where->add($updateQb->expr()->eq(
|
||||
|
@ -301,6 +304,33 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an exclusive read+write lock on a table
|
||||
*
|
||||
* @param string $tableName
|
||||
* @throws \BadMethodCallException When trying to acquire a second lock
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function lockTable($tableName) {
|
||||
if ($this->lockedTable !== null) {
|
||||
throw new \BadMethodCallException('Can not lock a new table until the previous lock is released.');
|
||||
}
|
||||
|
||||
$tableName = $this->tablePrefix . $tableName;
|
||||
$this->lockedTable = $tableName;
|
||||
$this->adapter->lockTable($tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release a previous acquired lock again
|
||||
*
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function unlockTable() {
|
||||
$this->adapter->unlockTable();
|
||||
$this->lockedTable = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the error code and message as a string for logging
|
||||
* works with DoctrineException
|
||||
|
|
|
@ -124,6 +124,25 @@ interface IDBConnection {
|
|||
*/
|
||||
public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []);
|
||||
|
||||
/**
|
||||
* Create an exclusive read+write lock on a table
|
||||
*
|
||||
* Important Note: Due to the nature how locks work on different DBs, it is
|
||||
* only possible to lock one table at a time. You should also NOT start a
|
||||
* transaction while holding a lock.
|
||||
*
|
||||
* @param string $tableName
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function lockTable($tableName);
|
||||
|
||||
/**
|
||||
* Release a previous acquired lock again
|
||||
*
|
||||
* @since 9.1.0
|
||||
*/
|
||||
public function unlockTable();
|
||||
|
||||
/**
|
||||
* Start a transaction
|
||||
* @since 6.0.0
|
||||
|
|
Loading…
Reference in New Issue