diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
index bc11daa3d..7da64480b 100644
--- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
+++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
@@ -393,7 +393,7 @@ class ClassMetadataFactory
if ( ! $definition) {
$sequenceName = $class->getTableName() . '_' . $class->getSingleIdentifierColumnName() . '_seq';
$definition['sequenceName'] = $this->_targetPlatform->fixSchemaElementName($sequenceName);
- $definition['allocationSize'] = 10;
+ $definition['allocationSize'] = 1;
$definition['initialValue'] = 1;
$class->setSequenceGeneratorDefinition($definition);
}
diff --git a/lib/Doctrine/ORM/Query/Lexer.php b/lib/Doctrine/ORM/Query/Lexer.php
index 57ffc3ebe..673ab0205 100644
--- a/lib/Doctrine/ORM/Query/Lexer.php
+++ b/lib/Doctrine/ORM/Query/Lexer.php
@@ -61,48 +61,52 @@ class Lexer extends \Doctrine\Common\Lexer
const T_BETWEEN = 107;
const T_BOTH = 108;
const T_BY = 109;
- const T_COUNT = 110;
- const T_DELETE = 111;
- const T_DESC = 112;
- const T_DISTINCT = 113;
- const T_EMPTY = 114;
- const T_ESCAPE = 115;
- const T_EXISTS = 116;
- const T_FALSE = 117;
- const T_FROM = 118;
- const T_GROUP = 119;
- const T_HAVING = 120;
- const T_IN = 121;
- const T_INDEX = 122;
- const T_INNER = 123;
- const T_INSTANCE = 124;
- const T_IS = 125;
- const T_JOIN = 126;
- const T_LEADING = 127;
- const T_LEFT = 128;
- const T_LIKE = 129;
- const T_MAX = 130;
- const T_MEMBER = 131;
- const T_MIN = 132;
- const T_NOT = 133;
- const T_NULL = 134;
- const T_OF = 135;
- const T_OR = 136;
- const T_ORDER = 137;
- const T_OUTER = 138;
- const T_SELECT = 139;
- const T_SET = 140;
- const T_SIZE = 141;
- const T_SOME = 142;
- const T_SUM = 143;
- const T_TRAILING = 144;
- const T_TRUE = 145;
- const T_UPDATE = 146;
- const T_WHERE = 147;
- const T_WITH = 148;
- const T_PARTIAL = 149;
- const T_MOD = 150;
-
+ const T_CASE = 110;
+ const T_COALESCE = 111;
+ const T_COUNT = 112;
+ const T_DELETE = 113;
+ const T_DESC = 114;
+ const T_DISTINCT = 115;
+ const T_EMPTY = 116;
+ const T_ESCAPE = 117;
+ const T_EXISTS = 118;
+ const T_FALSE = 119;
+ const T_FROM = 120;
+ const T_GROUP = 121;
+ const T_HAVING = 122;
+ const T_IN = 123;
+ const T_INDEX = 124;
+ const T_INNER = 125;
+ const T_INSTANCE = 126;
+ const T_IS = 127;
+ const T_JOIN = 128;
+ const T_LEADING = 129;
+ const T_LEFT = 130;
+ const T_LIKE = 131;
+ const T_MAX = 132;
+ const T_MEMBER = 133;
+ const T_MIN = 134;
+ const T_NOT = 135;
+ const T_NULL = 136;
+ const T_NULLIF = 137;
+ const T_OF = 138;
+ const T_OR = 139;
+ const T_ORDER = 140;
+ const T_OUTER = 141;
+ const T_SELECT = 142;
+ const T_SET = 143;
+ const T_SIZE = 144;
+ const T_SOME = 145;
+ const T_SUM = 146;
+ const T_TRAILING = 147;
+ const T_TRUE = 148;
+ const T_UPDATE = 149;
+ const T_WHEN = 150;
+ const T_WHERE = 151;
+ const T_WITH = 153;
+ const T_PARTIAL = 154;
+ const T_MOD = 155;
+
/**
* Creates a new query scanner object.
*
diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php
index 2a2fa70cd..8aa82e9dd 100644
--- a/lib/Doctrine/ORM/Query/Parser.php
+++ b/lib/Doctrine/ORM/Query/Parser.php
@@ -397,6 +397,45 @@ class Parser
return $peek;
}
+ /**
+ * Peek beyond the matched closing parenthesis and return the first token after that one.
+ *
+ * @return array
+ */
+ private function _peekBeyondClosingParenthesis()
+ {
+ $token = $this->_lexer->peek();
+ $numUnmatched = 1;
+
+ while ($numUnmatched > 0 && $token !== null) {
+ if ($token['value'] == ')') {
+ --$numUnmatched;
+ } else if ($token['value'] == '(') {
+ ++$numUnmatched;
+ }
+
+ $token = $this->_lexer->peek();
+ }
+
+ $this->_lexer->resetPeek();
+
+ return $token;
+ }
+
+ /**
+ * Checks if the given token indicates a mathematical operator.
+ *
+ * @return boolean TRUE is the token is a mathematical operator, FALSE otherwise.
+ */
+ private function _isMathOperator($token)
+ {
+ if (in_array($token['value'], array("+", "-", "/", "*"))) {
+ return true;
+ }
+
+ return false;
+ }
+
/**
* Checks if the next-next (after lookahead) token starts a function.
*
@@ -451,7 +490,7 @@ class Parser
}
/**
- * Validates that the given IdentificationVariable is a semantically correct.
+ * Validates that the given IdentificationVariable is semantically correct.
* It must exist in query components list.
*
* @return void
@@ -486,6 +525,12 @@ class Parser
}
}
+ /**
+ * Validates that the given PartialObjectExpression is semantically correct.
+ * It must exist in query components list.
+ *
+ * @return void
+ */
private function _processDeferredPartialObjectExpressions()
{
foreach ($this->_deferredPartialObjectExpressions as $deferredItem) {
@@ -511,7 +556,7 @@ class Parser
}
/**
- * Validates that the given ResultVariable is a semantically correct.
+ * Validates that the given ResultVariable is semantically correct.
* It must exist in query components list.
*
* @return void
@@ -547,7 +592,7 @@ class Parser
}
/**
- * Validates that the given PathExpression is a semantically correct for grammar rules:
+ * Validates that the given PathExpression is semantically correct for grammar rules:
*
* AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
* SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
@@ -1537,7 +1582,7 @@ class Parser
$peek = $this->_lexer->peek(); // lookahead => token after the token after the '.'
$this->_lexer->resetPeek();
- if ($peek['value'] == '+' || $peek['value'] == '-' || $peek['value'] == '/' || $peek['value'] == '*') {
+ if ($this->_isMathOperator($peek)) {
return $this->SimpleArithmeticExpression();
}
@@ -1545,6 +1590,14 @@ class Parser
} else if ($lookahead == Lexer::T_INTEGER || $lookahead == Lexer::T_FLOAT) {
return $this->SimpleArithmeticExpression();
} else if ($this->_isFunction()) {
+ // We may be in an ArithmeticExpression (find the matching ")" and inspect for Math operator)
+ $this->_lexer->peek(); // "("
+ $peek = $this->_peekBeyondClosingParenthesis();
+
+ if ($this->_isMathOperator($peek)) {
+ return $this->SimpleArithmeticExpression();
+ }
+
return $this->FunctionDeclaration();
} else if ($lookahead == Lexer::T_STRING) {
return $this->StringPrimary();
@@ -1603,7 +1656,12 @@ class Parser
$expression = $this->SimpleArithmeticExpression();
}
} else if ($this->_isFunction()) {
- if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
+ $this->_lexer->peek(); // "("
+ $beyond = $this->_peekBeyondClosingParenthesis();
+
+ if ($this->_isMathOperator($beyond)) {
+ $expression = $this->ScalarExpression();
+ } else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
$expression = $this->AggregateExpression();
} else {
// Shortcut: ScalarExpression => Function
@@ -1644,26 +1702,51 @@ class Parser
}
/**
- * SimpleSelectExpression ::= StateFieldPathExpression | IdentificationVariable | (AggregateExpression [["AS"] AliasResultVariable])
+ * SimpleSelectExpression ::=
+ * StateFieldPathExpression | IdentificationVariable |
+ * ((AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable])
*
* @return \Doctrine\ORM\Query\AST\SimpleSelectExpression
*/
public function SimpleSelectExpression()
{
- if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
- // SingleValuedPathExpression | IdentificationVariable
- $glimpse = $this->_lexer->glimpse();
+ $peek = $this->_lexer->glimpse();
- if ($glimpse['type'] == Lexer::T_DOT) {
- return new AST\SimpleSelectExpression($this->StateFieldPathExpression());
+ if ($peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) {
+ // SingleValuedPathExpression | IdentificationVariable
+ if ($peek['value'] == '.') {
+ $expression = $this->StateFieldPathExpression();
+ } else {
+ $expression = $this->IdentificationVariable();
}
- $this->match(Lexer::T_IDENTIFIER);
+ return new AST\SimpleSelectExpression($expression);
+ } else if ($this->_lexer->lookahead['value'] == '(') {
+ if ($peek['type'] == Lexer::T_SELECT) {
+ // Subselect
+ $this->match(Lexer::T_OPEN_PARENTHESIS);
+ $expression = $this->Subselect();
+ $this->match(Lexer::T_CLOSE_PARENTHESIS);
+ } else {
+ // Shortcut: ScalarExpression => SimpleArithmeticExpression
+ $expression = $this->SimpleArithmeticExpression();
+ }
- return new AST\SimpleSelectExpression($this->_lexer->token['value']);
+ return new AST\SimpleSelectExpression($expression);
}
- $expr = new AST\SimpleSelectExpression($this->AggregateExpression());
+ $this->_lexer->peek();
+ $beyond = $this->_peekBeyondClosingParenthesis();
+
+ if ($this->_isMathOperator($beyond)) {
+ $expression = $this->ScalarExpression();
+ } else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
+ $expression = $this->AggregateExpression();
+ } else {
+ $expression = $this->FunctionDeclaration();
+ }
+
+ $expr = new AST\SimpleSelectExpression($expression);
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
$this->match(Lexer::T_AS);
@@ -1869,23 +1952,6 @@ class Parser
}
}
- private function _peekBeyondClosingParenthesis()
- {
- $numUnmatched = 1;
- $token = $this->_lexer->peek();
- while ($numUnmatched > 0 && $token !== null) {
- if ($token['value'] == ')') {
- --$numUnmatched;
- } else if ($token['value'] == '(') {
- ++$numUnmatched;
- }
- $token = $this->_lexer->peek();
- }
- $this->_lexer->resetPeek();
-
- return $token;
- }
-
/**
* EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"
*
@@ -2355,13 +2421,13 @@ class Parser
}
/**
- * InExpression ::= StateFieldPathExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")"
+ * InExpression ::= SingleValuedPathExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")"
*
* @return \Doctrine\ORM\Query\AST\InExpression
*/
public function InExpression()
{
- $inExpression = new AST\InExpression($this->StateFieldPathExpression());
+ $inExpression = new AST\InExpression($this->SingleValuedPathExpression());
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
$this->match(Lexer::T_NOT);
diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php
index baaafcf77..e43965ee7 100644
--- a/lib/Doctrine/ORM/Query/SqlWalker.php
+++ b/lib/Doctrine/ORM/Query/SqlWalker.php
@@ -1106,7 +1106,7 @@ class SqlWalker implements TreeWalker
$expr = $simpleSelectExpression->expression;
if ($expr instanceof AST\PathExpression) {
- $sql .= ' ' . $this->walkPathExpression($expr);
+ $sql .= $this->walkPathExpression($expr);
} else if ($expr instanceof AST\AggregateExpression) {
if ( ! $simpleSelectExpression->fieldIdentificationVariable) {
$alias = $this->_scalarResultCounter++;
@@ -1114,17 +1114,55 @@ class SqlWalker implements TreeWalker
$alias = $simpleSelectExpression->fieldIdentificationVariable;
}
- $sql .= ' ' . $this->walkAggregateExpression($expr) . ' AS dctrn__' . $alias;
+ $sql .= $this->walkAggregateExpression($expr) . ' AS dctrn__' . $alias;
+ } else if ($expr instanceof AST\Subselect) {
+ if ( ! $simpleSelectExpression->fieldIdentificationVariable) {
+ $alias = $this->_scalarResultCounter++;
+ } else {
+ $alias = $simpleSelectExpression->fieldIdentificationVariable;
+ }
+
+ $columnAlias = 'sclr' . $this->_aliasCounter++;
+ $sql .= '(' . $this->walkSubselect($expr) . ') AS ' . $columnAlias;
+ $this->_scalarResultAliasMap[$alias] = $columnAlias;
+ } else if ($expr instanceof AST\Functions\FunctionNode) {
+ if ( ! $simpleSelectExpression->fieldIdentificationVariable) {
+ $alias = $this->_scalarResultCounter++;
+ } else {
+ $alias = $simpleSelectExpression->fieldIdentificationVariable;
+ }
+
+ $columnAlias = 'sclr' . $this->_aliasCounter++;
+ $sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias;
+ $this->_scalarResultAliasMap[$alias] = $columnAlias;
+ } else if (
+ $expr instanceof AST\SimpleArithmeticExpression ||
+ $expr instanceof AST\ArithmeticTerm ||
+ $expr instanceof AST\ArithmeticFactor ||
+ $expr instanceof AST\ArithmeticPrimary
+ ) {
+ if ( ! $simpleSelectExpression->fieldIdentificationVariable) {
+ $alias = $this->_scalarResultCounter++;
+ } else {
+ $alias = $simpleSelectExpression->fieldIdentificationVariable;
+ }
+
+ $columnAlias = 'sclr' . $this->_aliasCounter++;
+ $sql .= $this->walkSimpleArithmeticExpression($expr) . ' AS ' . $columnAlias;
+ $this->_scalarResultAliasMap[$alias] = $columnAlias;
} else {
// IdentificationVariable
- // FIXME: Composite key support, or select all columns? Does that make sense
- // in a subquery?
$class = $this->_queryComponents[$expr]['metadata'];
- $sql .= ' ' . $this->getSqlTableAlias($class->getTableName(), $expr) . '.'
- . $class->getQuotedColumnName($class->identifier[0], $this->_platform);
+ $tableAlias = $this->getSqlTableAlias($class->getTableName(), $expr);
+ $first = true;
+
+ foreach ($class->identifier as $identifier) {
+ if ($first) $first = false; else $sql .= ', ';
+ $sql .= $tableAlias . '.' . $class->getQuotedColumnName($identifier, $this->_platform);
+ }
}
- return $sql;
+ return ' ' . $sql;
}
/**
diff --git a/lib/Doctrine/ORM/Tools/EntityGenerator.php b/lib/Doctrine/ORM/Tools/EntityGenerator.php
index 8e353bda9..b32197895 100644
--- a/lib/Doctrine/ORM/Tools/EntityGenerator.php
+++ b/lib/Doctrine/ORM/Tools/EntityGenerator.php
@@ -513,7 +513,7 @@ public function ()
$methods[] = $code;
}
} else if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_MANY) {
- if ($associationMapping->isOwningSide) {
+ if ($associationMapping['isOwningSide']) {
if ($code = $this->_generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
$methods[] = $code;
}
diff --git a/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php b/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php
index 757d542ad..aab94c9dc 100644
--- a/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php
+++ b/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php
@@ -53,6 +53,7 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
}
$parser = new \Doctrine\ORM\Query\Parser($query);
+
// We do NOT test SQL output here. That only unnecessarily slows down the tests!
$parser->setCustomOutputTreeWalker('Doctrine\Tests\Mocks\MockTreeWalker');
@@ -134,6 +135,16 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN (1)');
}
+ public function testInExpressionWithSingleValuedAssociationPathExpression()
+ {
+ $this->assertValidDql("SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u WHERE u.avatar IN (?1, ?2)");
+ }
+
+ public function testInvalidInExpressionWithCollectionValuedAssociationPathExpression()
+ {
+ $this->assertInvalidDql("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.phonenumbers IN (?1, ?2)");
+ }
+
public function testInstanceOfExpressionSupportedInWherePart()
{
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyEmployee');
@@ -225,15 +236,25 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
$this->assertValidDql("SELECT u.name, (SELECT COUNT(p.phonenumber) FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234) pcount FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'");
}
- /*public function testSubselectInSelectPart2()
+ public function testArithmeticExpressionInSelectPart()
{
$this->assertValidDql("SELECT SUM(u.id) / COUNT(u.id) FROM Doctrine\Tests\Models\CMS\CmsUser u");
- }*/
+ }
- /*public function testSubselectInSelectPart3()
+ public function testArithmeticExpressionInSubselectPart()
{
$this->assertValidDql("SELECT (SELECT SUM(u.id) / COUNT(u.id) FROM Doctrine\Tests\Models\CMS\CmsUser u2) value FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'");
- }*/
+ }
+
+ public function testArithmeticExpressionWithParenthesisInSubselectPart()
+ {
+ $this->assertValidDql("SELECT (SELECT (SUM(u.id) / COUNT(u.id)) FROM Doctrine\Tests\Models\CMS\CmsUser u2) value FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'");
+ }
+
+ public function testDuplicateAliasInSubselectPart()
+ {
+ $this->assertInvalidDql("SELECT (SELECT SUM(u.id) / COUNT(u.id) AS foo FROM Doctrine\Tests\Models\CMS\CmsUser u2) foo FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'");
+ }
public function testPositionalInputParameter()
{
@@ -377,6 +398,11 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id > SOME (SELECT u2.id FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE u2.name = u.name)');
}
+ public function testArithmeticExpressionWithoutParenthesisInWhereClause()
+ {
+ $this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE SIZE(u.phonenumbers) + 1 > 10');
+ }
+
public function testMemberOfExpression()
{
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.phonenumbers');
diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php
index 7a664b400..2e0ff090d 100644
--- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php
+++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php
@@ -15,6 +15,14 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$this->_em = $this->_getTestEntityManager();
}
+ /**
+ * Assert a valid SQL generation.
+ *
+ * @param string $dqlToBeTested
+ * @param string $sqlToBeConfirmed
+ * @param array $queryHints
+ * @param array $queryParams
+ */
public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed, array $queryHints = array(), array $queryParams = array())
{
try {
@@ -38,6 +46,39 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
}
}
+ /**
+ * Asser an invalid SQL generation.
+ *
+ * @param string $dqlToBeTested
+ * @param string $expectedException
+ * @param array $queryHints
+ * @param array $queryParams
+ */
+ public function assertInvalidSqlGeneration($dqlToBeTested, $expectedException, array $queryHints = array(), array $queryParams = array())
+ {
+ $this->setExpectedException($expectedException);
+
+ $query = $this->_em->createQuery($dqlToBeTested);
+
+ foreach ($queryParams AS $name => $value) {
+ $query->setParameter($name, $value);
+ }
+
+ $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)
+ ->useQueryCache(false);
+
+ foreach ($queryHints AS $name => $value) {
+ $query->setHint($name, $value);
+ }
+
+ $sql = $query->getSql();
+ $query->free();
+
+ // If we reached here, test failed
+ $this->fail($sql);
+ }
+
+
public function testSupportsSelectForAllFields()
{
$this->assertSqlGeneration(
@@ -102,6 +143,33 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
);
}
+ public function testSelectCorrelatedSubqueryComplexMathematicalExpression()
+ {
+ $this->assertSqlGeneration(
+ 'SELECT (SELECT (count(p.phonenumber)+5)*10 FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p JOIN p.user ui WHERE ui.id = u.id) AS c FROM Doctrine\Tests\Models\CMS\CmsUser u',
+ 'SELECT (SELECT (count(c0_.phonenumber) + 5) * 10 AS sclr1 FROM cms_phonenumbers c0_ INNER JOIN cms_users c1_ ON c0_.user_id = c1_.id WHERE c1_.id = c2_.id) AS sclr0 FROM cms_users c2_'
+ );
+ }
+
+ public function testSelectComplexMathematicalExpression()
+ {
+ $this->assertSqlGeneration(
+ 'SELECT (count(p.phonenumber)+5)*10 FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p JOIN p.user ui WHERE ui.id = ?1',
+ 'SELECT (count(c0_.phonenumber) + 5) * 10 AS sclr0 FROM cms_phonenumbers c0_ INNER JOIN cms_users c1_ ON c0_.user_id = c1_.id WHERE c1_.id = ?'
+ );
+ }
+
+ /* NOT (YET?) SUPPORTED.
+ Can be supported if SimpleSelectExpresion supports SingleValuedPathExpression instead of StateFieldPathExpression.
+
+ public function testSingleAssociationPathExpressionInSubselect()
+ {
+ $this->assertSqlGeneration(
+ 'SELECT (SELECT p.user FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user = u) user_id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1',
+ 'SELECT (SELECT c0_.user_id FROM cms_phonenumbers c0_ WHERE c0_.user_id = c1_.id) AS sclr0 FROM cms_users c1_ WHERE c1_.id = ?'
+ );
+ }*/
+
public function testSupportsOrderByWithAscAsDefault()
{
$this->assertSqlGeneration(
@@ -347,6 +415,23 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
);
}
+ public function testInExpressionWithSingleValuedAssociationPathExpressionInWherePart()
+ {
+ $this->assertSqlGeneration(
+ 'SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u WHERE u.avatar IN (?1, ?2)',
+ 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.avatar_id IN (?, ?)'
+ );
+ }
+
+ public function testInvalidInExpressionWithSingleValuedAssociationPathExpressionOnInverseSide()
+ {
+ // We do not support SingleValuedAssociationPathExpression on inverse side
+ $this->assertInvalidSqlGeneration(
+ "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.address IN (?1, ?2)",
+ "Doctrine\ORM\Query\QueryException"
+ );
+ }
+
public function testSupportsConcatFunctionForMysqlAndPostgresql()
{
$connMock = $this->_em->getConnection();