diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 692dfdee2f67..cbd14d4e79b2 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -816,14 +816,15 @@ protected function runQueryCallback($query, $bindings, Closure $callback) // message to include the bindings with SQL, which will make this exception a // lot more helpful to the developer instead of just the database's errors. catch (Exception $e) { + $maskBindings = Arr::get($this->config, 'mask_bindings_on_exception_message', false); if ($this->isUniqueConstraintError($e)) { throw new UniqueConstraintViolationException( - $this->getName(), $query, $this->prepareBindings($bindings), $e + $this->getName(), $query, $this->prepareBindings($bindings), $e, $maskBindings ); } throw new QueryException( - $this->getName(), $query, $this->prepareBindings($bindings), $e + $this->getName(), $query, $this->prepareBindings($bindings), $e, $maskBindings ); } } diff --git a/src/Illuminate/Database/QueryException.php b/src/Illuminate/Database/QueryException.php index 84aebb1a670b..57232629a94c 100644 --- a/src/Illuminate/Database/QueryException.php +++ b/src/Illuminate/Database/QueryException.php @@ -38,7 +38,7 @@ class QueryException extends PDOException * @param \Throwable $previous * @return void */ - public function __construct($connectionName, $sql, array $bindings, Throwable $previous) + public function __construct($connectionName, $sql, array $bindings, Throwable $previous, bool $maskBindings = false) { parent::__construct('', 0, $previous); @@ -46,7 +46,7 @@ public function __construct($connectionName, $sql, array $bindings, Throwable $p $this->sql = $sql; $this->bindings = $bindings; $this->code = $previous->getCode(); - $this->message = $this->formatMessage($connectionName, $sql, $bindings, $previous); + $this->message = $this->formatMessage($connectionName, $sql, $bindings, $previous, $maskBindings); if ($previous instanceof PDOException) { $this->errorInfo = $previous->errorInfo; @@ -60,11 +60,16 @@ public function __construct($connectionName, $sql, array $bindings, Throwable $p * @param string $sql * @param array $bindings * @param \Throwable $previous + * @param bool $maskBindings * @return string */ - protected function formatMessage($connectionName, $sql, $bindings, Throwable $previous) + protected function formatMessage($connectionName, $sql, $bindings, Throwable $previous, bool $maskBindings) { - return $previous->getMessage().' (Connection: '.$connectionName.', SQL: '.Str::replaceArray('?', $bindings, $sql).')'; + if (! $maskBindings) { + $sql = Str::replaceArray('?', $bindings, $sql); + } + + return $previous->getMessage().' (Connection: '.$connectionName.', SQL: '.$sql.')'; } /** diff --git a/tests/Database/DatabaseConnectionTest.php b/tests/Database/DatabaseConnectionTest.php index 1b6211386a04..d0c62021e6ef 100755 --- a/tests/Database/DatabaseConnectionTest.php +++ b/tests/Database/DatabaseConnectionTest.php @@ -540,6 +540,40 @@ public function testGetRawQueryLog() $this->assertEquals(1.23, $log[0]['time']); } + public function testQueryExceptionMessageOnNoMasking() + { + $this->expectException(QueryException::class); + $this->expectExceptionMessage('server has gone away (Connection: , SQL: SELECT * FROM users WHERE id = 1)'); + + $pdo = m::mock(PDO::class); + $pdo->shouldReceive('beginTransaction')->once(); + $statement = m::mock(PDOStatement::class); + $statement->shouldReceive('bindValue')->once(); + $pdo->shouldReceive('prepare')->once()->andReturn($statement); + $statement->shouldReceive('execute')->once()->andThrow(new PDOException('server has gone away')); + + $connection = new Connection($pdo); + $connection->beginTransaction(); + $connection->statement('SELECT * FROM users WHERE id = ?', [1]); + } + + public function testQueryExceptionMessageOnMasking() + { + $this->expectException(QueryException::class); + $this->expectExceptionMessage('server has gone away (Connection: , SQL: SELECT * FROM users WHERE id = ?)'); + + $pdo = m::mock(PDO::class); + $pdo->shouldReceive('beginTransaction')->once(); + $statement = m::mock(PDOStatement::class); + $statement->shouldReceive('bindValue')->once(); + $pdo->shouldReceive('prepare')->once()->andReturn($statement); + $statement->shouldReceive('execute')->once()->andThrow(new PDOException('server has gone away')); + + $connection = new Connection($pdo, '', '', ['mask_bindings_on_exception_message' => true]); + $connection->beginTransaction(); + $connection->statement('SELECT * FROM users WHERE id = ?', [1]); + } + protected function getMockConnection($methods = [], $pdo = null) { $pdo = $pdo ?: new DatabaseConnectionTestMockPDO;