From 635b422880a9d911c7c2398842c2fbcc597b6757 Mon Sep 17 00:00:00 2001 From: Alex Pott Date: Thu, 28 May 2020 14:59:19 +0100 Subject: [PATCH] Issue #3133798 by Beakerboy, daffie: Semicolon removed from query even when it is allowed --- core/lib/Drupal/Core/Database/Connection.php | 6 +- .../Tests/Core/Database/ConnectionTest.php | 55 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php index 3eea3cf7658..00a91f9a6fa 100644 --- a/core/lib/Drupal/Core/Database/Connection.php +++ b/core/lib/Drupal/Core/Database/Connection.php @@ -628,7 +628,11 @@ abstract class Connection { // semicolons should only be needed for special cases like defining a // function or stored procedure in SQL. Trim any trailing delimiter to // minimize false positives. - $query = rtrim($query, "; \t\n\r\0\x0B"); + $trim_chars = " \t\n\r\0\x0B"; + if (empty($options['allow_delimiter_in_query'])) { + $trim_chars .= ';'; + } + $query = rtrim($query, $trim_chars); if (strpos($query, ';') !== FALSE && empty($options['allow_delimiter_in_query'])) { throw new \InvalidArgumentException('; is not supported in SQL strings. Use only one statement at a time.'); } diff --git a/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php b/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php index 8325079986b..2c2e565ab79 100644 --- a/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php +++ b/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\Core\Database; use Drupal\Tests\Core\Database\Stub\StubConnection; +use Drupal\Tests\Core\Database\Stub\StubPDO; use Drupal\Tests\UnitTestCase; /** @@ -297,4 +298,58 @@ class ConnectionTest extends UnitTestCase { ); } + /** + * Test rtrim() of query strings. + * + * @dataProvider provideQueriesToTrim + */ + public function testQueryTrim($expected, $query, $options) { + $mock_pdo = $this->getMockBuilder(StubPdo::class) + ->setMethods(['execute', 'prepare', 'setAttribute']) + ->getMock(); + + // Ensure that PDO::prepare() is called only once, and with the + // correctly trimmed query string. + $mock_pdo->expects($this->once()) + ->method('prepare') + ->with($expected) + ->willReturnSelf(); + $connection = new StubConnection($mock_pdo, []); + $connection->query($query, [], $options); + } + + /** + * Dataprovider for testQueryTrim(). + * + * @return array + * Array of arrays with the following elements: + * - Expected trimmed query. + * - Padded query. + * - Query options. + */ + public function provideQueriesToTrim() { + return [ + 'remove_semicolon' => [ + 'SELECT * FROM test', + 'SELECT * FROM test;', + [], + ], + 'keep_trailing_semicolon' => [ + 'SELECT * FROM test;', + 'SELECT * FROM test;', + ['allow_delimiter_in_query' => TRUE], + ], + 'remove_semicolon_with_whitespace' => [ + 'SELECT * FROM test', + 'SELECT * FROM test; ', + [], + ], + 'keep_trailing_semicolon_with_whitespace' => [ + 'SELECT * FROM test;', + 'SELECT * FROM test; ', + ['allow_delimiter_in_query' => TRUE], + ], + ]; + } + }