From 74ba0f68db092437a166db938cd0f2ef071296bb Mon Sep 17 00:00:00 2001 From: Nathaniel Catchpole Date: Mon, 17 Sep 2018 11:37:28 +0100 Subject: [PATCH] Issue #2142107 by drunken monkey, gilsbert, David_Rothstein, mondrake, Kristi Wachter: Complex cloned query dependent on __toString() call --- .../lib/Drupal/Core/Database/Query/Select.php | 7 +++++ .../Core/Database/SelectCloneTest.php | 31 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/core/lib/Drupal/Core/Database/Query/Select.php b/core/lib/Drupal/Core/Database/Query/Select.php index c38638a75d1..fe88f841728 100644 --- a/core/lib/Drupal/Core/Database/Query/Select.php +++ b/core/lib/Drupal/Core/Database/Query/Select.php @@ -914,6 +914,8 @@ class Select extends Query implements SelectInterface { * {@inheritdoc} */ public function __clone() { + parent::__clone(); + // On cloning, also clone the dependent objects. However, we do not // want to clone the database connection object as that would duplicate the // connection itself. @@ -923,6 +925,11 @@ class Select extends Query implements SelectInterface { foreach ($this->union as $key => $aggregate) { $this->union[$key]['query'] = clone($aggregate['query']); } + foreach ($this->tables as $alias => $table) { + if ($table['table'] instanceof SelectInterface) { + $this->tables[$alias]['table'] = clone $table['table']; + } + } } } diff --git a/core/tests/Drupal/KernelTests/Core/Database/SelectCloneTest.php b/core/tests/Drupal/KernelTests/Core/Database/SelectCloneTest.php index 30a4f1b9410..3b14283b345 100644 --- a/core/tests/Drupal/KernelTests/Core/Database/SelectCloneTest.php +++ b/core/tests/Drupal/KernelTests/Core/Database/SelectCloneTest.php @@ -22,6 +22,10 @@ class SelectCloneTest extends DatabaseTestBase { $query->condition('id', $subquery, 'IN'); $clone = clone $query; + + // Cloned query should have a different unique identifier. + $this->assertNotEquals($query->uniqueIdentifier(), $clone->uniqueIdentifier()); + // Cloned query should not be altered by the following modification // happening on original query. $subquery->condition('age', 25, '>'); @@ -34,4 +38,31 @@ class SelectCloneTest extends DatabaseTestBase { $this->assertEqual(2, $query_result, 'The query returns the expected number of rows'); } + /** + * Tests that nested SELECT queries are cloned properly. + */ + public function testNestedQueryCloning() { + $sub_query = $this->connection->select('test', 't'); + $sub_query->addField('t', 'id', 'id'); + $sub_query->condition('age', 28, '<'); + + $query = $this->connection->select($sub_query, 't'); + + $clone = clone $query; + + // Cloned query should have a different unique identifier. + $this->assertNotEquals($query->uniqueIdentifier(), $clone->uniqueIdentifier()); + + // Cloned query should not be altered by the following modification + // happening on original query. + $sub_query->condition('age', 25, '>'); + + $clone_result = $clone->countQuery()->execute()->fetchField(); + $query_result = $query->countQuery()->execute()->fetchField(); + + // Make sure the cloned query has not been modified. + $this->assertEquals(3, $clone_result, 'The cloned query returns the expected number of rows'); + $this->assertEquals(2, $query_result, 'The query returns the expected number of rows'); + } + }