Skip to content

Commit

Permalink
Merge remote branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
jwage committed May 20, 2010
2 parents 2d7f769 + 5bbe6c7 commit 35f66ab
Show file tree
Hide file tree
Showing 40 changed files with 1,675 additions and 162 deletions.
4 changes: 2 additions & 2 deletions lib/Doctrine/DBAL/Connection.php
Expand Up @@ -753,7 +753,7 @@ public function beginTransaction()
public function commit()
{
if ($this->_transactionNestingLevel == 0) {
throw ConnectionException::commitFailedNoActiveTransaction();
throw ConnectionException::noActiveTransaction();
}
if ($this->_isRollbackOnly) {
throw ConnectionException::commitFailedRollbackOnly();
Expand All @@ -779,7 +779,7 @@ public function commit()
public function rollback()
{
if ($this->_transactionNestingLevel == 0) {
throw ConnectionException::rollbackFailedNoActiveTransaction();
throw ConnectionException::noActiveTransaction();
}

$this->connect();
Expand Down
3 changes: 2 additions & 1 deletion lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php
Expand Up @@ -175,7 +175,8 @@ public function fetchAll($fetchStyle = PDO::FETCH_BOTH)
}

$result = array();
oci_fetch_all($this->_sth, $result, 0, -1, self::$fetchStyleMap[$fetchStyle] | OCI_RETURN_NULLS | OCI_FETCHSTATEMENT_BY_ROW);
oci_fetch_all($this->_sth, $result, 0, -1,
self::$fetchStyleMap[$fetchStyle] | OCI_RETURN_NULLS | OCI_FETCHSTATEMENT_BY_ROW | OCI_RETURN_LOBS);

return $result;
}
Expand Down
42 changes: 42 additions & 0 deletions lib/Doctrine/DBAL/LockMode.php
@@ -0,0 +1,42 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\DBAL;

/**
* Contains all ORM LockModes
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 1.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Roman Borschel <roman@code-factory.org>
*/
class LockMode
{
const NONE = 0;
const OPTIMISTIC = 1;
const PESSIMISTIC_READ = 2;
const PESSIMISTIC_WRITE = 4;

final private function __construct() { }
}
39 changes: 38 additions & 1 deletion lib/Doctrine/DBAL/Platforms/AbstractPlatform.php
Expand Up @@ -488,11 +488,48 @@ public function getCosExpression($value)
return 'COS(' . $value . ')';
}

public function getForUpdateSql()
public function getForUpdateSQL()
{
return 'FOR UPDATE';
}

/**
* Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
*
* @param string $fromClause
* @param int $lockMode
* @return string
*/
public function appendLockHint($fromClause, $lockMode)
{
return $fromClause;
}

/**
* Get the sql snippet to append to any SELECT statement which locks rows in shared read lock.
*
* This defaults to the ASNI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database
* vendors allow to lighten this constraint up to be a real read lock.
*
* @return string
*/
public function getReadLockSQL()
{
return $this->getForUpdateSQL();
}

/**
* Get the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows.
*
* The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ASNI SQL standard.
*
* @return string
*/
public function getWriteLockSQL()
{
return $this->getForUpdateSQL();
}

public function getDropDatabaseSQL($database)
{
return 'DROP DATABASE ' . $database;
Expand Down
5 changes: 5 additions & 0 deletions lib/Doctrine/DBAL/Platforms/DB2Platform.php
Expand Up @@ -513,4 +513,9 @@ public function getSQLResultCasing($column)
{
return strtoupper($column);
}

public function getForUpdateSQL()
{
return ' WITH RR USE AND KEEP UPDATE LOCKS';
}
}
28 changes: 28 additions & 0 deletions lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php
Expand Up @@ -483,4 +483,32 @@ public function getTruncateTableSQL($tableName, $cascade = false)
{
return 'TRUNCATE TABLE '.$tableName;
}

/**
* MsSql uses Table Hints for locking strategies instead of the ANSI SQL FOR UPDATE like hints.
*
* @return string
*/
public function getForUpdateSQL()
{
return '';
}

/**
* @license LGPL
* @author Hibernate
* @param string $fromClause
* @param int $lockMode
* @return string
*/
public function appendLockHint($fromClause, $lockMode)
{
if ($lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) {
return $fromClause . " WITH (UPDLOCK, ROWLOCK)";
} else if ( $lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_READ ) {
return $fromClause . " WITH (HOLDLOCK, ROWLOCK)";
} else {
return $fromClause;
}
}
}
5 changes: 5 additions & 0 deletions lib/Doctrine/DBAL/Platforms/MySqlPlatform.php
Expand Up @@ -583,4 +583,9 @@ public function createsExplicitIndexForForeignKeys()
{
return true;
}

public function getReadLockSQL()
{
return 'LOCK IN SHARE MODE';
}
}
5 changes: 5 additions & 0 deletions lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php
Expand Up @@ -637,4 +637,9 @@ public function getTruncateTableSQL($tableName, $cascade = false)
{
return 'TRUNCATE '.$tableName.' '.($cascade)?'CASCADE':'';
}

public function getReadLockSQL()
{
return 'FOR SHARE';
}
}
5 changes: 5 additions & 0 deletions lib/Doctrine/DBAL/Platforms/SqlitePlatform.php
Expand Up @@ -428,4 +428,9 @@ static public function udfLocate($str, $substr, $offset = 0)
}
return 0;
}

public function getForUpdateSql()
{
return '';
}
}
2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/AbstractQuery.php
Expand Up @@ -463,7 +463,7 @@ public function getHint($name)
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
{
return $this->_em->newHydrator($this->_hydrationMode)->iterate(
$this->_doExecute($params, $hydrationMode), $this->_resultSetMapping
$this->_doExecute($params, $hydrationMode), $this->_resultSetMapping, $this->_hints
);
}

Expand Down
21 changes: 19 additions & 2 deletions lib/Doctrine/ORM/EntityManager.php
Expand Up @@ -22,6 +22,7 @@
use Closure, Exception,
Doctrine\Common\EventManager,
Doctrine\DBAL\Connection,
Doctrine\DBAL\LockMode,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\ClassMetadataFactory,
Doctrine\ORM\Proxy\ProxyFactory;
Expand Down Expand Up @@ -318,11 +319,13 @@ public function flush()
*
* @param string $entityName
* @param mixed $identifier
* @param int $lockMode
* @param int $lockVersion
* @return object
*/
public function find($entityName, $identifier)
public function find($entityName, $identifier, $lockMode = LockMode::NONE, $lockVersion = null)
{
return $this->getRepository($entityName)->find($identifier);
return $this->getRepository($entityName)->find($identifier, $lockMode, $lockVersion);
}

/**
Expand Down Expand Up @@ -478,6 +481,20 @@ public function copy($entity, $deep = false)
throw new \BadMethodCallException("Not implemented.");
}

/**
* Acquire a lock on the given entity.
*
* @param object $entity
* @param int $lockMode
* @param int $lockVersion
* @throws OptimisticLockException
* @throws PessimisticLockException
*/
public function lock($entity, $lockMode, $lockVersion = null)
{
$this->_unitOfWork->lock($entity, $lockMode, $lockVersion);
}

/**
* Gets the repository for an entity class.
*
Expand Down
32 changes: 28 additions & 4 deletions lib/Doctrine/ORM/EntityRepository.php
Expand Up @@ -19,6 +19,8 @@

namespace Doctrine\ORM;

use Doctrine\DBAL\LockMode;

/**
* An EntityRepository serves as a repository for entities with generic as well as
* business specific methods for retrieving entities.
Expand Down Expand Up @@ -87,23 +89,45 @@ public function clear()
* Finds an entity by its primary key / identifier.
*
* @param $id The identifier.
* @param int $hydrationMode The hydration mode to use.
* @param int $lockMode
* @param int $lockVersion
* @return object The entity.
*/
public function find($id)
public function find($id, $lockMode = LockMode::NONE, $lockVersion = null)
{
// Check identity map first
if ($entity = $this->_em->getUnitOfWork()->tryGetById($id, $this->_class->rootEntityName)) {
if ($lockMode != LockMode::NONE) {
$this->_em->lock($entity, $lockMode, $lockVersion);
}

return $entity; // Hit!
}

if ( ! is_array($id) || count($id) <= 1) {
//FIXME: Not correct. Relies on specific order.
// @todo FIXME: Not correct. Relies on specific order.
$value = is_array($id) ? array_values($id) : array($id);
$id = array_combine($this->_class->identifier, $value);
}

return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id);
if ($lockMode == LockMode::NONE) {
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id);
} else if ($lockMode == LockMode::OPTIMISTIC) {
if (!$this->_class->isVersioned) {
throw OptimisticLockException::notVersioned($this->_entityName);
}
$entity = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id);

$this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion);

return $entity;
} else {
if (!$this->_em->getConnection()->isTransactionActive()) {
throw TransactionRequiredException::transactionRequired();
}

return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id, null, null, array(), $lockMode);
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php
Expand Up @@ -134,4 +134,4 @@ final class PostUpdate extends Annotation {}
final class PreRemove extends Annotation {}
final class PostRemove extends Annotation {}
final class PostLoad extends Annotation {}
final class OnFlush extends Annotation {}

11 changes: 11 additions & 0 deletions lib/Doctrine/ORM/OptimisticLockException.php
Expand Up @@ -24,6 +24,7 @@
* that uses optimistic locking through a version field fails.
*
* @author Roman Borschel <roman@code-factory.org>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @since 2.0
*/
class OptimisticLockException extends ORMException
Expand All @@ -49,4 +50,14 @@ public static function lockFailed($entity)
{
return new self("The optimistic lock on an entity failed.", $entity);
}

public static function lockFailedVersionMissmatch($entity, $expectedLockVersion, $actualLockVersion)
{
return new self("The optimistic lock failed, version " . $expectedLockVersion . " was expected, but is actually ".$actualLockVersion, $entity);
}

public static function notVersioned($entityName)
{
return new self("Cannot obtain optimistic lock on unversioned entity " . $entityName, null);
}
}

0 comments on commit 35f66ab

Please sign in to comment.