1
0
mirror of synced 2024-12-05 03:06:05 +03:00

DQL : Multiple join bug fixed

DQL : Changed cartesian product fetching to inner join fetching
This commit is contained in:
doctrine 2006-05-23 12:12:54 +00:00
parent fcf706182d
commit 47e1cf515e
4 changed files with 80 additions and 36 deletions

View File

@ -22,6 +22,8 @@ class Doctrine_Query extends Doctrine_Access {
private $collections = array();
private $joined = array();
private $joins = array();
/**
* @var array $data fetched data
*/
@ -101,6 +103,7 @@ class Doctrine_Query extends Doctrine_Access {
$this->connectors = array();
$this->collections = array();
$this->joined = array();
$this->joins = array();
}
/**
* loadFields
@ -167,6 +170,9 @@ class Doctrine_Query extends Doctrine_Access {
$this->parts[$name] = $args[0];
break;
case "from":
$this->parts['columns'] = array();
$this->joins = array();
default:
$this->parts[$name] = array();
$this->$method($args[0]);
@ -209,6 +215,9 @@ class Doctrine_Query extends Doctrine_Access {
$this->parts[$name] = $value;
break;
case "from":
$this->parts['columns'] = array();
$this->joins = array();
default:
$this->parts[$name] = array();
$this->$method($value);
@ -230,14 +239,15 @@ class Doctrine_Query extends Doctrine_Access {
// build the basic query
$q = "SELECT ".implode(", ",$this->parts["columns"]).
" FROM ";
foreach($this->parts["from"] as $tname => $bool) {
$str = $tname;
if(isset($this->parts["join"][$tname]))
$str .= " ".$this->parts["join"][$tname];
$a[] = $str;
$a[] = $tname;
}
$q .= implode(", ",$a);
if( ! empty($this->parts['join']))
$q .= " ".implode(' ', $this->parts["join"]);
$this->applyInheritance();
if( ! empty($this->parts["where"]))
$q .= " WHERE ".implode(" ",$this->parts["where"]);
@ -345,7 +355,7 @@ class Doctrine_Query extends Doctrine_Access {
final public function getData($key) {
if(isset($this->data[$key]) && is_array($this->data[$key]))
return $this->data[$key];
return array();
}
/**
@ -395,17 +405,18 @@ class Doctrine_Query extends Doctrine_Access {
$previd = array();
$coll = $this->getCollection($root);
$coll = $this->getCollection($root);
$prev[$root] = $coll;
$array = $this->parseData($stmt);
$colls = array();
foreach($array as $data):
foreach($array as $data) {
/**
* remove duplicated data rows and map data into objects
*/
foreach($data as $key => $row):
foreach($data as $key => $row) {
if(empty($row))
continue;
@ -416,24 +427,31 @@ class Doctrine_Query extends Doctrine_Access {
if($previd[$name] !== $row) {
// set internal data
$this->tables[$name]->setData($row);
// initialize a new record
$record = $this->tables[$name]->getRecord();
if($name == $root) {
// add record into root collection
$coll->add($record);
} else {
$last = $coll->getLast();
if( ! $last->hasReference($name))
$last->initReference($this->getCollection($name),$this->connectors[$name]);
$pointer = $this->joins[$name];
$last = $prev[$pointer]->getLast();
if( ! $last->hasReference($name)) {
$prev[$name] = $this->getCollection($name);
$last->initReference($prev[$name],$this->connectors[$name]);
}
$last->addReference($record);
}
}
$previd[$name] = $row;
endforeach;
endforeach;
}
}
return $coll;
endswitch;
@ -866,18 +884,20 @@ class Doctrine_Query extends Doctrine_Access {
switch($fk->getType()):
case Doctrine_Relation::ONE_AGGREGATE:
case Doctrine_Relation::ONE_COMPOSITE:
$this->parts["where"][] = "(".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign().")";
$this->parts["from"][$tname] = true;
$this->parts["from"][$tname2] = true;
//$this->parts["where"][] = "(".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign().")";
//$this->parts["from"][$tname] = true;
//$this->parts["from"][$tname2] = true;
$this->parts["join"][$tname] = "INNER JOIN ".$tname2." ON ".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign();
break;
case Doctrine_Relation::MANY_AGGREGATE:
case Doctrine_Relation::MANY_COMPOSITE:
$this->parts["join"][$tname] = "LEFT JOIN ".$tname2." ON ".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign();
$this->joined[] = $tname2;
$this->parts["from"][$tname] = true;
break;
endswitch;
$c = $objTable->getComponentName();
$this->joins[$name] = $c;
} elseif($fk instanceof Doctrine_Association) {
$asf = $fk->getAssociationFactory();

View File

@ -205,7 +205,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
case Doctrine_Identifier::SEQUENCE:
if($exists) {
$name = $this->table->getIdentifier();
if(isset($this->data[$name]))
$this->id = $this->data[$name];
@ -246,14 +246,16 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->data[$k] = array();
}
return array_keys(get_object_vars($this));
}
/**
* __wakeup
* unseralize
* this method is automatically called everytime a Doctrine_Record object is unserialized
*
* @return void
*/
public function __wakeup() {
$this->modified = array();
$this->state = Doctrine_Record::STATE_CLEAN;
@ -301,21 +303,27 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
}
/**
* hasCollections
* @return boolean whether or not this dao is part of a collection
* whether or not this record is part of a collection
*
* @return boolean
*/
final public function hasCollections() {
return (! empty($this->collections));
}
/**
* getState
* returns the current state of the object
*
* @see Doctrine_Record::STATE_* constants
* @return integer the current state
* @return integer
*/
final public function getState() {
return $this->state;
}
/**
* refresh refresh internal data from the database
* refresh
* refresh internal data from the database
*
* @return boolean
*/
final public function refresh() {
@ -377,7 +385,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
}
/**
* get
* returns a value of a property or related component
* returns a value of a property or a related component
*
* @param $name name of the property or related component
* @throws InvalidKeyException

View File

@ -32,13 +32,15 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$thread = $board->Threads[0];
$thread->Entries[0]->topic = "My first topic";
$thread->Entries[1]->topic = "My second topic";
$this->assertEqual($thread->Entries[0]->topic, "My first topic");
$this->assertEqual($thread->Entries[0]->getState(), Doctrine_Record::STATE_TDIRTY);
$this->assertTrue($thread->Entries[0] instanceof Forum_Entry);
$this->session->flush();
$q = new Doctrine_Query($this->session);
$board->getTable()->clear();
$board = $board->getTable()->find($board->getID());
$this->assertEqual($board->Threads->count(), 1);
$this->assertEqual($board->name, "Doctrine Forum");
@ -48,7 +50,7 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertTrue($board->Threads[0] instanceof Forum_Thread);
$q = new Doctrine_Query($this->session);
$q->from("Forum_Board");
$coll = $q->execute();
$this->assertEqual($coll->count(), 1);
@ -56,6 +58,20 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$q->from("Forum_Board, Forum_Board.Threads");
$coll = $q->execute();
$this->assertEqual($coll->count(), 1);
$q->from("Forum_Board-l, Forum_Board.Threads-l");
$this->assertEqual($q->getQuery(), "SELECT forum_board.id AS Forum_Board__id, forum_thread.id AS Forum_Thread__id FROM forum_board LEFT JOIN forum_thread ON forum_board.id = forum_thread.board_id");
$q->from("Forum_Board-l, Forum_Board.Threads-l, Forum_Board.Threads.Entries-l");
$this->assertEqual($q->getQuery(), "SELECT forum_board.id AS Forum_Board__id, forum_thread.id AS Forum_Thread__id, forum_entry.id AS Forum_Entry__id FROM forum_board LEFT JOIN forum_thread ON forum_board.id = forum_thread.board_id LEFT JOIN forum_entry ON forum_thread.id = forum_entry.thread_id");
$boards = $q->execute();
$this->assertEqual($boards->count(), 1);
$count = count($this->dbh);
$this->assertEqual($boards[0]->Threads->count(), 1);
$this->assertEqual(count($this->dbh), $count);
$this->assertEqual($boards[0]->Threads[0]->Entries->count(), 1);
$this->assertEqual(count($this->dbh), $count);
}
public function testQueryWithAliases() {
@ -141,9 +157,10 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
}
public function testOrderBy() {
$query = new Doctrine_Query($this->session);
$users = $query->query("FROM User-b ORDER BY User.name ASC, User.Email.address");
$query->from("User-b")->orderby("User.name ASC, User.Email.address");
$users = $query->execute();
$this->assertEqual(trim($query->getQuery()),
"SELECT entity.id AS User__id FROM entity, email WHERE (entity.email_id = email.id) AND (entity.type = 0) ORDER BY entity.name ASC, email.address");
"SELECT entity.id AS User__id FROM entity INNER JOIN email ON entity.email_id = email.id WHERE (entity.type = 0) ORDER BY entity.name ASC, email.address");
$this->assertEqual($users->count(),8);
$this->assertTrue($users[0]->name == "Arnold Schwarzenegger");
}
@ -286,11 +303,12 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$users = $query->query("FROM User-b, User.Email-b");
$this->assertEqual(trim($query->getQuery()),
"SELECT entity.id AS User__id, email.id AS Email__id FROM entity, email WHERE (entity.email_id = email.id) AND (entity.type = 0)");
"SELECT entity.id AS User__id, email.id AS Email__id FROM entity INNER JOIN email ON entity.email_id = email.id WHERE (entity.type = 0)");
$this->assertEqual($users->count(),8);
$users = $query->query("FROM Email-b WHERE Email.address LIKE '%@example%'");
$this->assertEqual($query->getQuery(),
"SELECT email.id AS Email__id FROM email WHERE (email.address LIKE '%@example%')");
$this->assertEqual($users->count(),8);
@ -323,7 +341,7 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertTrue(is_array($values));
$this->assertTrue(isset($values['users']));
$this->assertTrue(isset($values['max']));
}
}
}
?>

View File

@ -52,10 +52,8 @@ class Doctrine_UnitTestCase extends UnitTestCase {
$this->prepareTables();
$this->prepareData();
}
public function prepareTables() {
public function prepareTables() {
foreach($this->tables as $name) {
$this->dbh->query("DROP TABLE IF EXISTS ".strtolower($name));
}