Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[DDC-719] Fixed issue with Empty and also Size function that were gen…

…erating an incorrect SQL for associations counting.
  • Loading branch information...
commit 35af98260a525a841c05be15f52f8df455000066 1 parent 623c02c
authored August 06, 2010
69  lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php
@@ -45,45 +45,66 @@ class SizeFunction extends FunctionNode
45 45
      */
46 46
     public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
47 47
     {
  48
+        $platform = $sqlWalker->getConnection()->getDatabasePlatform();
48 49
         $dqlAlias = $this->collectionPathExpression->identificationVariable;
49 50
         $assocField = $this->collectionPathExpression->field;
50 51
         
51 52
         $qComp = $sqlWalker->getQueryComponent($dqlAlias);
52  
-        $assoc = $qComp['metadata']->associationMappings[$assocField];
53  
-        $sql = '';
54  
-        
  53
+        $class = $qComp['metadata'];
  54
+        $assoc = $class->associationMappings[$assocField];
  55
+        $sql = 'SELECT COUNT(*) FROM ';
  56
+
55 57
         if ($assoc->isOneToMany()) {
56 58
             $targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc->targetEntityName);
57  
-            $targetAssoc = $targetClass->associationMappings[$assoc->mappedBy];
58  
-            
59 59
             $targetTableAlias = $sqlWalker->getSqlTableAlias($targetClass->table['name']);
60  
-            $sourceTableAlias = $sqlWalker->getSqlTableAlias($qComp['metadata']->table['name'], $dqlAlias);
61  
-            
62  
-            $whereSql = '';
  60
+            $sourceTableAlias = $sqlWalker->getSqlTableAlias($class->table['name'], $dqlAlias);
63 61
 
64  
-            foreach ($targetAssoc->targetToSourceKeyColumns as $targetKeyColumn => $sourceKeyColumn) {
65  
-                $whereSql .= (($whereSql == '') ? ' WHERE ' : ' AND ')
66  
-                           . $targetTableAlias . '.' . $sourceKeyColumn . ' = ' 
67  
-                           . $sourceTableAlias . '.' . $targetKeyColumn;
68  
-            }
  62
+            $sql .= $targetClass->getQuotedTableName($platform) . ' ' . $targetTableAlias . ' WHERE ';
  63
+
  64
+            $owningAssoc = $targetClass->associationMappings[$assoc->mappedBy];
69 65
 
70  
-            $tableName = $targetClass->table['name'];
71  
-        } else if ($assoc->isManyToMany()) {
72  
-            $targetTableAlias = $sqlWalker->getSqlTableAlias($assoc->joinTable['name']);
73  
-            $sourceTableAlias = $sqlWalker->getSqlTableAlias($qComp['metadata']->table['name'], $dqlAlias);
  66
+            $first = true;
74 67
             
75  
-            $whereSql = '';
  68
+            foreach ($owningAssoc->targetToSourceKeyColumns as $targetColumn => $sourceColumn) {
  69
+                if ($first) $first = false; else $sql .= ' AND ';
76 70
 
77  
-            foreach ($assoc->relationToSourceKeyColumns as $targetKeyColumn => $sourceKeyColumn) {
78  
-                $whereSql .= (($whereSql == '') ? ' WHERE ' : ' AND ')
79  
-                           . $targetTableAlias . '.' . $targetKeyColumn . ' = ' 
80  
-                           . $sourceTableAlias . '.' . $sourceKeyColumn;
  71
+                $sql .= $targetTableAlias . '.' . $sourceColumn
  72
+                      . ' = '
  73
+                      . $sourceTableAlias . '.' . $class->getQuotedColumnName($class->fieldNames[$targetColumn], $platform);
81 74
             }
  75
+        } else { // many-to-many
  76
+            $targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc->targetEntityName);
  77
+
  78
+            $owningAssoc = $assoc->isOwningSide ? $assoc : $targetClass->associationMappings[$assoc->mappedBy];
  79
+            $joinTable = $owningAssoc->joinTable;
82 80
 
83  
-            $tableName = $assoc->joinTable['name'];
  81
+            // SQL table aliases
  82
+            $joinTableAlias = $sqlWalker->getSqlTableAlias($joinTable['name']);
  83
+            $sourceTableAlias = $sqlWalker->getSqlTableAlias($class->table['name'], $dqlAlias);
  84
+
  85
+            // join to target table
  86
+            $sql .= $owningAssoc->getQuotedJoinTableName($platform) . ' ' . $joinTableAlias . ' WHERE ';
  87
+
  88
+            $joinColumns = $assoc->isOwningSide
  89
+                ? $joinTable['joinColumns']
  90
+                : $joinTable['inverseJoinColumns'];
  91
+
  92
+            $first = true;
  93
+
  94
+            foreach ($joinColumns as $joinColumn) {
  95
+                if ($first) $first = false; else $sql .= ' AND ';
  96
+
  97
+                $sourceColumnName = $class->getQuotedColumnName(
  98
+                    $class->fieldNames[$joinColumn['referencedColumnName']], $platform
  99
+                );
  100
+
  101
+                $sql .= $joinTableAlias . '.' . $joinColumn['name']
  102
+                      . ' = '
  103
+                      . $sourceTableAlias . '.' . $sourceColumnName;
  104
+            }
84 105
         }
85 106
         
86  
-        return '(SELECT COUNT(*) FROM ' . $tableName . ' ' . $targetTableAlias . $whereSql . ')';
  107
+        return '(' . $sql . ')';
87 108
     }
88 109
 
89 110
     /**
4  lib/Doctrine/ORM/Query/SqlWalker.php
@@ -1393,7 +1393,7 @@ public function walkCollectionMemberExpression($collMemberExpr)
1393 1393
             $targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
1394 1394
             
1395 1395
             $owningAssoc = $assoc->isOwningSide ? $assoc : $targetClass->associationMappings[$assoc->mappedBy];
1396  
-            $joinTable = $assoc->isOwningSide ? $assoc->joinTable : $owningAssoc->joinTable;
  1396
+            $joinTable = $owningAssoc->joinTable;
1397 1397
             
1398 1398
             // SQL table aliases
1399 1399
             $joinTableAlias = $this->getSqlTableAlias($joinTable['name']);
@@ -1401,7 +1401,7 @@ public function walkCollectionMemberExpression($collMemberExpr)
1401 1401
             $sourceTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
1402 1402
             
1403 1403
             // join to target table
1404  
-            $sql .= $assoc->getQuotedJoinTableName($this->_platform)
  1404
+            $sql .= $owningAssoc->getQuotedJoinTableName($this->_platform)
1405 1405
                   . ' ' . $joinTableAlias . ' INNER JOIN '
1406 1406
                   . $targetClass->getQuotedTableName($this->_platform)
1407 1407
                   . ' ' . $targetTableAlias . ' ON ';
107  tests/Doctrine/Tests/ORM/Functional/Ticket/DDC719Test.php
... ...
@@ -0,0 +1,107 @@
  1
+<?php
  2
+
  3
+namespace Doctrine\Tests\ORM\Functional\Ticket;
  4
+
  5
+require_once __DIR__ . '/../../../TestInit.php';
  6
+
  7
+class DDC719Test extends \Doctrine\Tests\OrmFunctionalTestCase
  8
+{
  9
+    protected function setUp()
  10
+    {
  11
+        parent::setUp();
  12
+        //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
  13
+        $this->_schemaTool->createSchema(array(
  14
+            $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC719Group'),
  15
+        ));
  16
+    }
  17
+
  18
+    public function testIsEmptySqlGeneration()
  19
+    {
  20
+        $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');
  21
+
  22
+        $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());
  23
+    }
  24
+}
  25
+
  26
+/**
  27
+ * @MappedSuperclass
  28
+ */
  29
+class Entity
  30
+{
  31
+    /** 
  32
+     * @Id @GeneratedValue
  33
+     * @Column(type="integer") 
  34
+     */
  35
+    protected $id;
  36
+    
  37
+    public function getId() { return $this->id; }
  38
+}
  39
+
  40
+/**
  41
+ * @Entity
  42
+ * @Table(name="groups")
  43
+ */
  44
+class DDC719Group extends Entity {
  45
+    /** @Column(type="string", nullable=false) */
  46
+    protected $name;
  47
+
  48
+	/** @Column(type="string", nullable=true) */
  49
+	protected $description;
  50
+
  51
+	/**
  52
+	 * @ManyToMany(targetEntity="DDC719Group", inversedBy="parents")
  53
+	 * @JoinTable(name="groups_groups",
  54
+	 * 		joinColumns={@JoinColumn(name="parent_id", referencedColumnName="id")},
  55
+	 * 		inverseJoinColumns={@JoinColumn(name="child_id", referencedColumnName="id")}
  56
+	 * )
  57
+	 */
  58
+	protected $children = NULL;
  59
+
  60
+	/**
  61
+	 * @ManyToMany(targetEntity="DDC719Group", mappedBy="children")
  62
+	 */
  63
+	protected $parents = NULL;
  64
+
  65
+	/**
  66
+	 * construct
  67
+	 */
  68
+	public function __construct() {
  69
+		parent::__construct();
  70
+
  71
+		$this->channels = new ArrayCollection();
  72
+		$this->children = new ArrayCollection();
  73
+		$this->parents = new ArrayCollection();
  74
+	}
  75
+
  76
+	/**
  77
+	 * adds group as new child
  78
+	 *
  79
+	 * @param Group $child
  80
+	 * @todo check against endless recursion
  81
+	 * @todo check if the group is already member of the group
  82
+	 */
  83
+	public function addGroup(Group $child) {
  84
+		$this->children->add($child);
  85
+	}
  86
+
  87
+	/**
  88
+	 * adds channel as new child
  89
+	 *
  90
+	 * @param Channel $child
  91
+	 * @todo check if the channel is already member of the group
  92
+	 */
  93
+	public function addChannel(Channel $child) {
  94
+		$this->channels->add($child);
  95
+	}
  96
+
  97
+	/**
  98
+	 * getter & setter
  99
+	 */
  100
+	public function getName() { return $this->name; }
  101
+	public function setName($name) { $this->name = $name; }
  102
+	public function getDescription() { return $this->description; }
  103
+	public function setDescription($description) { $this->description = $description; }
  104
+	public function getChildren() { return $this->children; }
  105
+	public function getParents() { return $this->parents; }
  106
+	public function getChannels() { return $this->channels; }
  107
+}

0 notes on commit 35af982

Please sign in to comment.
Something went wrong with that request. Please try again.