Skip to content

Commit

Permalink
Allow reconnect in transaction by setting transactions to 0 (#15931)
Browse files Browse the repository at this point in the history
  • Loading branch information
halaei authored and taylorotwell committed Oct 18, 2016
1 parent 6f21736 commit 01f350e
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 20 deletions.
7 changes: 1 addition & 6 deletions src/Illuminate/Database/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Exception;
use Throwable;
use LogicException;
use RuntimeException;
use DateTimeInterface;
use Illuminate\Support\Arr;
use Illuminate\Database\Query\Expression;
Expand Down Expand Up @@ -985,14 +984,10 @@ public function getReadPdo()
*
* @param \PDO|null $pdo
* @return $this
*
* @throws \RuntimeException
*/
public function setPdo($pdo)
{
if ($this->transactions >= 1) {
throw new RuntimeException("Can't swap PDO instance while within transaction.");
}
$this->transactions = 0;

$this->pdo = $pdo;

Expand Down
46 changes: 32 additions & 14 deletions tests/Database/DatabaseConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,14 @@ public function testBeginTransactionMethodNeverRetriesIfWithinTransaction()
}
}

public function testCantSwapPDOWithOpenTransaction()
public function testSwapPDOWithOpenTransactionResetsTransactionLevel()
{
$pdo = $this->createMock('DatabaseConnectionTestMockPDO');
$pdo->expects($this->once())->method('beginTransaction')->will($this->returnValue(true));
$connection = $this->getMockConnection([], $pdo);
$connection->beginTransaction();
$this->setExpectedException('RuntimeException', "Can't swap PDO instance while within transaction.");
$connection->disconnect();
$this->assertEquals(0, $connection->transactionLevel());
}

public function testBeganTransactionFiresEventsIfSet()
Expand Down Expand Up @@ -240,24 +240,42 @@ public function testTransactionMethodRollsbackAndThrows()
}

/**
* @expectedException RuntimeException
* @expectedException \Illuminate\Database\QueryException
*/
public function testTransactionMethodDisallowPDOChanging()
public function testOnLostConnectionPDOIsNotSwappedWithinATransaction()
{
$pdo = $this->getMockBuilder('DatabaseConnectionTestMockPDO')->setMethods(['beginTransaction', 'commit', 'rollBack'])->getMock();
$pdo->expects($this->once())->method('beginTransaction');
$pdo->expects($this->once())->method('rollBack');
$pdo->expects($this->never())->method('commit');
$pdo = m::mock(PDO::class);
$pdo->shouldReceive('beginTransaction')->once();
$statement = m::mock(PDOStatement::class);
$pdo->shouldReceive('prepare')->once()->andReturn($statement);
$statement->shouldReceive('execute')->once()->andThrow(new PDOException('server has gone away'));

$mock = $this->getMockConnection([], $pdo);
$connection = new \Illuminate\Database\Connection($pdo);
$connection->beginTransaction();
$connection->statement('foo');
}

$mock->setReconnector(function ($connection) {
$connection->setPDO(null);
});
public function testOnLostConnectionPDOIsSwappedOutsideTransaction()
{
$pdo = m::mock(PDO::class);

$statement = m::mock(PDOStatement::class);
$statement->shouldReceive('execute')->once()->andThrow(new PDOException('server has gone away'));
$statement->shouldReceive('execute')->once()->andReturn('result');

$pdo->shouldReceive('prepare')->twice()->andReturn($statement);

$mock->transaction(function ($connection) {
$connection->reconnect();
$connection = new \Illuminate\Database\Connection($pdo);

$called = false;

$connection->setReconnector(function ($connection) use (&$called) {
$called = true;
});

$this->assertEquals('result', $connection->statement('foo'));

$this->assertTrue($called);
}

public function testRunMethodRetriesOnFailure()
Expand Down

0 comments on commit 01f350e

Please sign in to comment.