Merge branch 'fix/#6464-#6475-correct-SQL-generated-with-JTI-and-WITH-condition-2.5' into 2.5
Backport #6464 Backport #6475
This commit is contained in:
commit
d89d238594
@ -870,6 +870,19 @@ class SqlWalker implements TreeWalker
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function walkRangeVariableDeclaration($rangeVariableDeclaration)
|
public function walkRangeVariableDeclaration($rangeVariableDeclaration)
|
||||||
|
{
|
||||||
|
return $this->generateRangeVariableDeclarationSQL($rangeVariableDeclaration, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate appropriate SQL for RangeVariableDeclaration AST node
|
||||||
|
*
|
||||||
|
* @param AST\RangeVariableDeclaration $rangeVariableDeclaration
|
||||||
|
* @param bool $buildNestedJoins
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function generateRangeVariableDeclarationSQL($rangeVariableDeclaration, $buildNestedJoins)
|
||||||
{
|
{
|
||||||
$class = $this->em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName);
|
$class = $this->em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName);
|
||||||
$dqlAlias = $rangeVariableDeclaration->aliasIdentificationVariable;
|
$dqlAlias = $rangeVariableDeclaration->aliasIdentificationVariable;
|
||||||
@ -885,7 +898,11 @@ class SqlWalker implements TreeWalker
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ($class->isInheritanceTypeJoined()) {
|
if ($class->isInheritanceTypeJoined()) {
|
||||||
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
|
if ($buildNestedJoins) {
|
||||||
|
$sql = '(' . $sql . $this->_generateClassTableInheritanceJoins($class, $dqlAlias) . ')';
|
||||||
|
} else {
|
||||||
|
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $sql;
|
return $sql;
|
||||||
@ -1121,16 +1138,17 @@ class SqlWalker implements TreeWalker
|
|||||||
: ' INNER JOIN ';
|
: ' INNER JOIN ';
|
||||||
|
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case ($joinDeclaration instanceof \Doctrine\ORM\Query\AST\RangeVariableDeclaration):
|
case ($joinDeclaration instanceof AST\RangeVariableDeclaration):
|
||||||
$class = $this->em->getClassMetadata($joinDeclaration->abstractSchemaName);
|
$class = $this->em->getClassMetadata($joinDeclaration->abstractSchemaName);
|
||||||
$dqlAlias = $joinDeclaration->aliasIdentificationVariable;
|
$dqlAlias = $joinDeclaration->aliasIdentificationVariable;
|
||||||
$tableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
|
$tableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||||
$condition = '(' . $this->walkConditionalExpression($join->conditionalExpression) . ')';
|
$condition = '(' . $this->walkConditionalExpression($join->conditionalExpression) . ')';
|
||||||
$condExprConjunction = ($class->isInheritanceTypeJoined() && $joinType != AST\Join::JOIN_TYPE_LEFT && $joinType != AST\Join::JOIN_TYPE_LEFTOUTER)
|
$isUnconditionalJoin = empty($conditions);
|
||||||
|
$condExprConjunction = ($class->isInheritanceTypeJoined() && $joinType != AST\Join::JOIN_TYPE_LEFT && $joinType != AST\Join::JOIN_TYPE_LEFTOUTER && $isUnconditionalJoin)
|
||||||
? ' AND '
|
? ' AND '
|
||||||
: ' ON ';
|
: ' ON ';
|
||||||
|
|
||||||
$sql .= $this->walkRangeVariableDeclaration($joinDeclaration);
|
$sql .= $this->generateRangeVariableDeclarationSQL($joinDeclaration, !$isUnconditionalJoin);
|
||||||
|
|
||||||
$conditions = array($condition);
|
$conditions = array($condition);
|
||||||
|
|
||||||
@ -1151,7 +1169,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$sql .= $condExprConjunction . implode(' AND ', $conditions);
|
$sql .= $condExprConjunction . implode(' AND ', $conditions);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ($joinDeclaration instanceof \Doctrine\ORM\Query\AST\JoinAssociationDeclaration):
|
case ($joinDeclaration instanceof AST\JoinAssociationDeclaration):
|
||||||
$sql .= $this->walkJoinAssociationDeclaration($joinDeclaration, $joinType, $join->conditionalExpression);
|
$sql .= $this->walkJoinAssociationDeclaration($joinDeclaration, $joinType, $join->conditionalExpression);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
76
tests/Doctrine/Tests/ORM/Functional/Ticket/GH6464Test.php
Normal file
76
tests/Doctrine/Tests/ORM/Functional/Ticket/GH6464Test.php
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||||
|
|
||||||
|
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group GH-6464
|
||||||
|
*/
|
||||||
|
class GH6464Test extends OrmFunctionalTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->_schemaTool->createSchema([
|
||||||
|
$this->_em->getClassMetadata(GH6464Post::class),
|
||||||
|
$this->_em->getClassMetadata(GH6464User::class),
|
||||||
|
$this->_em->getClassMetadata(GH6464Author::class),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies that SqlWalker generates valid SQL for an INNER JOIN to CTI table
|
||||||
|
*
|
||||||
|
* SqlWalker needs to generate nested INNER JOIN statements, otherwise there would be INNER JOIN
|
||||||
|
* statements without an ON clause, which are valid on e.g. MySQL but rejected by PostgreSQL.
|
||||||
|
*/
|
||||||
|
public function testIssue()
|
||||||
|
{
|
||||||
|
$query = $this->_em->createQueryBuilder()
|
||||||
|
->select('p')
|
||||||
|
->from(GH6464Post::class, 'p')
|
||||||
|
->innerJoin(GH6464Author::class, 'a', 'WITH', 'p.authorId = a.id')
|
||||||
|
->getQuery();
|
||||||
|
|
||||||
|
$this->assertNotRegExp(
|
||||||
|
'/INNER JOIN \w+ \w+ INNER JOIN/',
|
||||||
|
$query->getSQL(),
|
||||||
|
'As of GH-6464, every INNER JOIN should have an ON clause, which is missing here'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Query shouldn't yield a result, yet it shouldn't crash (anymore)
|
||||||
|
$this->assertEquals([], $query->getResult());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @Entity */
|
||||||
|
class GH6464Post
|
||||||
|
{
|
||||||
|
/** @Id @Column(type="integer") @GeneratedValue */
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/** @Column(type="integer") */
|
||||||
|
public $authorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
* @InheritanceType("JOINED")
|
||||||
|
* @DiscriminatorColumn(name="discr", type="string")
|
||||||
|
* @DiscriminatorMap({"author" = "GH6464Author"})
|
||||||
|
*/
|
||||||
|
abstract class GH6464User
|
||||||
|
{
|
||||||
|
/** @Id @Column(type="integer") @GeneratedValue */
|
||||||
|
public $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @Entity */
|
||||||
|
class GH6464Author extends GH6464User
|
||||||
|
{
|
||||||
|
}
|
@ -153,12 +153,12 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
{
|
{
|
||||||
$this->assertSqlGeneration(
|
$this->assertSqlGeneration(
|
||||||
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e JOIN Doctrine\Tests\Models\Company\CompanyManager m WITH e.id = m.id',
|
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e JOIN Doctrine\Tests\Models\Company\CompanyManager m WITH e.id = m.id',
|
||||||
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c0_.discr AS discr_5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id INNER JOIN company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id AND (c0_.id = c3_.id)'
|
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c0_.discr AS discr_5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id INNER JOIN (company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id) ON (c0_.id = c3_.id)'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertSqlGeneration(
|
$this->assertSqlGeneration(
|
||||||
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e LEFT JOIN Doctrine\Tests\Models\Company\CompanyManager m WITH e.id = m.id',
|
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e LEFT JOIN Doctrine\Tests\Models\Company\CompanyManager m WITH e.id = m.id',
|
||||||
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c0_.discr AS discr_5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id ON (c0_.id = c3_.id)'
|
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c0_.discr AS discr_5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN (company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id) ON (c0_.id = c3_.id)'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2165,7 +2165,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
// the where clause when not joining onto that table
|
// the where clause when not joining onto that table
|
||||||
$this->assertSqlGeneration(
|
$this->assertSqlGeneration(
|
||||||
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c LEFT JOIN Doctrine\Tests\Models\Company\CompanyEmployee e WITH e.id = c.salesPerson WHERE c.completed = true',
|
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c LEFT JOIN Doctrine\Tests\Models\Company\CompanyEmployee e WITH e.id = c.salesPerson WHERE c.completed = true',
|
||||||
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6 FROM company_contracts c0_ LEFT JOIN company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id ON (c2_.id = c0_.salesPerson_id) WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
|
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6 FROM company_contracts c0_ LEFT JOIN (company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id) ON (c2_.id = c0_.salesPerson_id) WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user