[DDC-719] Fixed issue with Empty and also Size function that were generating an incorrect SQL for associations counting.
This commit is contained in:
parent
623c02c7dc
commit
35af98260a
@ -45,45 +45,66 @@ class SizeFunction extends FunctionNode
|
||||
*/
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
{
|
||||
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
|
||||
$dqlAlias = $this->collectionPathExpression->identificationVariable;
|
||||
$assocField = $this->collectionPathExpression->field;
|
||||
|
||||
$qComp = $sqlWalker->getQueryComponent($dqlAlias);
|
||||
$assoc = $qComp['metadata']->associationMappings[$assocField];
|
||||
$sql = '';
|
||||
|
||||
$class = $qComp['metadata'];
|
||||
$assoc = $class->associationMappings[$assocField];
|
||||
$sql = 'SELECT COUNT(*) FROM ';
|
||||
|
||||
if ($assoc->isOneToMany()) {
|
||||
$targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc->targetEntityName);
|
||||
$targetAssoc = $targetClass->associationMappings[$assoc->mappedBy];
|
||||
|
||||
$targetTableAlias = $sqlWalker->getSqlTableAlias($targetClass->table['name']);
|
||||
$sourceTableAlias = $sqlWalker->getSqlTableAlias($qComp['metadata']->table['name'], $dqlAlias);
|
||||
$sourceTableAlias = $sqlWalker->getSqlTableAlias($class->table['name'], $dqlAlias);
|
||||
|
||||
$sql .= $targetClass->getQuotedTableName($platform) . ' ' . $targetTableAlias . ' WHERE ';
|
||||
|
||||
$owningAssoc = $targetClass->associationMappings[$assoc->mappedBy];
|
||||
|
||||
$first = true;
|
||||
|
||||
$whereSql = '';
|
||||
foreach ($owningAssoc->targetToSourceKeyColumns as $targetColumn => $sourceColumn) {
|
||||
if ($first) $first = false; else $sql .= ' AND ';
|
||||
|
||||
foreach ($targetAssoc->targetToSourceKeyColumns as $targetKeyColumn => $sourceKeyColumn) {
|
||||
$whereSql .= (($whereSql == '') ? ' WHERE ' : ' AND ')
|
||||
. $targetTableAlias . '.' . $sourceKeyColumn . ' = '
|
||||
. $sourceTableAlias . '.' . $targetKeyColumn;
|
||||
$sql .= $targetTableAlias . '.' . $sourceColumn
|
||||
. ' = '
|
||||
. $sourceTableAlias . '.' . $class->getQuotedColumnName($class->fieldNames[$targetColumn], $platform);
|
||||
}
|
||||
} else { // many-to-many
|
||||
$targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc->targetEntityName);
|
||||
|
||||
$tableName = $targetClass->table['name'];
|
||||
} else if ($assoc->isManyToMany()) {
|
||||
$targetTableAlias = $sqlWalker->getSqlTableAlias($assoc->joinTable['name']);
|
||||
$sourceTableAlias = $sqlWalker->getSqlTableAlias($qComp['metadata']->table['name'], $dqlAlias);
|
||||
|
||||
$whereSql = '';
|
||||
$owningAssoc = $assoc->isOwningSide ? $assoc : $targetClass->associationMappings[$assoc->mappedBy];
|
||||
$joinTable = $owningAssoc->joinTable;
|
||||
|
||||
foreach ($assoc->relationToSourceKeyColumns as $targetKeyColumn => $sourceKeyColumn) {
|
||||
$whereSql .= (($whereSql == '') ? ' WHERE ' : ' AND ')
|
||||
. $targetTableAlias . '.' . $targetKeyColumn . ' = '
|
||||
. $sourceTableAlias . '.' . $sourceKeyColumn;
|
||||
// SQL table aliases
|
||||
$joinTableAlias = $sqlWalker->getSqlTableAlias($joinTable['name']);
|
||||
$sourceTableAlias = $sqlWalker->getSqlTableAlias($class->table['name'], $dqlAlias);
|
||||
|
||||
// join to target table
|
||||
$sql .= $owningAssoc->getQuotedJoinTableName($platform) . ' ' . $joinTableAlias . ' WHERE ';
|
||||
|
||||
$joinColumns = $assoc->isOwningSide
|
||||
? $joinTable['joinColumns']
|
||||
: $joinTable['inverseJoinColumns'];
|
||||
|
||||
$first = true;
|
||||
|
||||
foreach ($joinColumns as $joinColumn) {
|
||||
if ($first) $first = false; else $sql .= ' AND ';
|
||||
|
||||
$sourceColumnName = $class->getQuotedColumnName(
|
||||
$class->fieldNames[$joinColumn['referencedColumnName']], $platform
|
||||
);
|
||||
|
||||
$sql .= $joinTableAlias . '.' . $joinColumn['name']
|
||||
. ' = '
|
||||
. $sourceTableAlias . '.' . $sourceColumnName;
|
||||
}
|
||||
|
||||
$tableName = $assoc->joinTable['name'];
|
||||
}
|
||||
|
||||
return '(SELECT COUNT(*) FROM ' . $tableName . ' ' . $targetTableAlias . $whereSql . ')';
|
||||
return '(' . $sql . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1393,7 +1393,7 @@ class SqlWalker implements TreeWalker
|
||||
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
|
||||
|
||||
$owningAssoc = $assoc->isOwningSide ? $assoc : $targetClass->associationMappings[$assoc->mappedBy];
|
||||
$joinTable = $assoc->isOwningSide ? $assoc->joinTable : $owningAssoc->joinTable;
|
||||
$joinTable = $owningAssoc->joinTable;
|
||||
|
||||
// SQL table aliases
|
||||
$joinTableAlias = $this->getSqlTableAlias($joinTable['name']);
|
||||
@ -1401,7 +1401,7 @@ class SqlWalker implements TreeWalker
|
||||
$sourceTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
|
||||
|
||||
// join to target table
|
||||
$sql .= $assoc->getQuotedJoinTableName($this->_platform)
|
||||
$sql .= $owningAssoc->getQuotedJoinTableName($this->_platform)
|
||||
. ' ' . $joinTableAlias . ' INNER JOIN '
|
||||
. $targetClass->getQuotedTableName($this->_platform)
|
||||
. ' ' . $targetTableAlias . ' ON ';
|
||||
|
107
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC719Test.php
Normal file
107
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC719Test.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
class DDC719Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC719Group'),
|
||||
));
|
||||
}
|
||||
|
||||
public function testIsEmptySqlGeneration()
|
||||
{
|
||||
$q = $this->_em->createQuery('SELECT g, c FROM Doctrine\Tests\ORM\Functional\Ticket\DDC719Group g LEFT JOIN g.children c WHERE g.parents IS EMPTY');
|
||||
|
||||
$this->assertEquals('SELECT g0_.name AS name0, g0_.description AS description1, g0_.id AS id2, g1_.name AS name3, g1_.description AS description4, g1_.id AS id5 FROM groups g0_ LEFT JOIN groups_groups g2_ ON g0_.id = g2_.parent_id LEFT JOIN groups g1_ ON g1_.id = g2_.child_id WHERE (SELECT COUNT(*) FROM groups_groups g3_ WHERE g3_.child_id = g0_.id) = 0', $q->getSQL());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @MappedSuperclass
|
||||
*/
|
||||
class Entity
|
||||
{
|
||||
/**
|
||||
* @Id @GeneratedValue
|
||||
* @Column(type="integer")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
public function getId() { return $this->id; }
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="groups")
|
||||
*/
|
||||
class DDC719Group extends Entity {
|
||||
/** @Column(type="string", nullable=false) */
|
||||
protected $name;
|
||||
|
||||
/** @Column(type="string", nullable=true) */
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity="DDC719Group", inversedBy="parents")
|
||||
* @JoinTable(name="groups_groups",
|
||||
* joinColumns={@JoinColumn(name="parent_id", referencedColumnName="id")},
|
||||
* inverseJoinColumns={@JoinColumn(name="child_id", referencedColumnName="id")}
|
||||
* )
|
||||
*/
|
||||
protected $children = NULL;
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity="DDC719Group", mappedBy="children")
|
||||
*/
|
||||
protected $parents = NULL;
|
||||
|
||||
/**
|
||||
* construct
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->channels = new ArrayCollection();
|
||||
$this->children = new ArrayCollection();
|
||||
$this->parents = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* adds group as new child
|
||||
*
|
||||
* @param Group $child
|
||||
* @todo check against endless recursion
|
||||
* @todo check if the group is already member of the group
|
||||
*/
|
||||
public function addGroup(Group $child) {
|
||||
$this->children->add($child);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds channel as new child
|
||||
*
|
||||
* @param Channel $child
|
||||
* @todo check if the channel is already member of the group
|
||||
*/
|
||||
public function addChannel(Channel $child) {
|
||||
$this->channels->add($child);
|
||||
}
|
||||
|
||||
/**
|
||||
* getter & setter
|
||||
*/
|
||||
public function getName() { return $this->name; }
|
||||
public function setName($name) { $this->name = $name; }
|
||||
public function getDescription() { return $this->description; }
|
||||
public function setDescription($description) { $this->description = $description; }
|
||||
public function getChildren() { return $this->children; }
|
||||
public function getParents() { return $this->parents; }
|
||||
public function getChannels() { return $this->channels; }
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user