diff --git a/lib/Doctrine/ORM/Query.php b/lib/Doctrine/ORM/Query.php index 91bf92279..44fb0b800 100644 --- a/lib/Doctrine/ORM/Query.php +++ b/lib/Doctrine/ORM/Query.php @@ -77,6 +77,11 @@ final class Query extends AbstractQuery const HINT_CUSTOM_TREE_WALKERS = 'doctrine.customTreeWalkers'; //const HINT_READ_ONLY = 'doctrine.readOnly'; + /** + * @var string + */ + const HINT_INTERNAL_ITERATION = 'doctrine.internal.iteration'; + /** * @var integer $_state The current state of this query. */ @@ -419,4 +424,18 @@ final class Query extends AbstractQuery { return $this->_maxResults; } + + /** + * Executes the query and returns an IterableResult that can be used to incrementally + * iterated over the result. + * + * @param array $params The query parameters. + * @param integer $hydrationMode The hydration mode to use. + * @return IterableResult + */ + public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT) + { + $this->setHint(self::HINT_INTERNAL_ITERATION, true); + return parent::iterate($params, $hydrationMode); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/QueryException.php b/lib/Doctrine/ORM/Query/QueryException.php index 151c9fa97..22753e228 100644 --- a/lib/Doctrine/ORM/Query/QueryException.php +++ b/lib/Doctrine/ORM/Query/QueryException.php @@ -63,4 +63,15 @@ class QueryException extends \Doctrine\Common\DoctrineException { return new self("Invalid parameter: token ".$key." is not defined in the query."); } + + /** + * @param Doctrine\ORM\Mapping\AssociationMapping $assoc + */ + public static function iterateWithFetchJoinCollectionNotAllowed($assoc) + { + return new self( + "Invalid query operation: Not allowed to iterate over fetch join collections ". + "in class ".$assoc->sourceEntityName." assocation ".$assoc->sourceFieldName + ); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index cc3ff2fcf..7a28fc6c2 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -55,8 +55,11 @@ class SqlWalker implements TreeWalker /** The Connection of the EntityManager. */ private $_conn; - /** The Query instance. */ + /** + * @var AbstractQuery + */ private $_query; + private $_dqlToSqlAliasMap = array(); /** Map from result variable names to their SQL column alias names. */ @@ -650,6 +653,12 @@ class SqlWalker implements TreeWalker $assoc = $relation; } + if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true) { + if ($relation->isOneToMany() || $relation->isManyToMany()) { + throw QueryException::iterateWithFetchJoinNotAllowed($assoc); + } + } + if ($assoc->isOneToOne()) { $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON '; $first = true; diff --git a/tests/Doctrine/Tests/ORM/Functional/QueryTest.php b/tests/Doctrine/Tests/ORM/Functional/QueryTest.php index 614a9d989..4565f0320 100644 --- a/tests/Doctrine/Tests/ORM/Functional/QueryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/QueryTest.php @@ -176,6 +176,15 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->_em->clear(); } + /** + * @expectedException \Doctrine\ORM\Query\QueryException + */ + public function testIterateResult_FetchJoinedCollection_ThrowsException() + { + $query = $this->_em->createQuery("SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.articles a"); + $articles = $query->iterate(); + } + public function testFluentQueryInterface() { $q = $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a");