1
0
mirror of synced 2024-12-14 15:16:04 +03:00

Fix DDC-2234

This commit is contained in:
Fabio B. Silva 2013-01-18 23:18:50 -02:00
parent b30b06852b
commit 4dcd5a1286
3 changed files with 141 additions and 69 deletions

View File

@ -2400,76 +2400,92 @@ class Parser
*/ */
public function SimpleConditionalExpression() public function SimpleConditionalExpression()
{ {
$token = $this->lexer->lookahead; if ($this->lexer->isNextToken(Lexer::T_EXISTS)) {
return $this->ExistsExpression();
}
$token = $this->lexer->lookahead;
$peek = $this->lexer->glimpse();
$lookahead = $token;
if ($this->lexer->isNextToken(Lexer::T_NOT)) { if ($this->lexer->isNextToken(Lexer::T_NOT)) {
$token = $this->lexer->glimpse(); $token = $this->lexer->glimpse();
} }
if ($token['type'] === Lexer::T_EXISTS) { if ($token['type'] === Lexer::T_IDENTIFIER || $token['type'] === Lexer::T_INPUT_PARAMETER || $this->isFunction()) {
return $this->ExistsExpression(); // Peek beyond the matching closing paranthesis.
} $beyond = $this->lexer->peek();
$peek = $this->lexer->glimpse(); switch ($peek['value']) {
case '(':
//Peeks beyond the matched closing parenthesis.
$token = $this->peekBeyondClosingParenthesis(false);
if ($token['type'] === Lexer::T_IDENTIFIER || $token['type'] === Lexer::T_INPUT_PARAMETER) { if ($token['type'] === Lexer::T_NOT) {
if ($peek['value'] == '(') { $token = $this->lexer->peek();
// Peek beyond the matching closing paranthesis ')' }
$this->lexer->peek();
$token = $this->peekBeyondClosingParenthesis(false);
if ($token['type'] === Lexer::T_NOT) { if ($token['type'] === Lexer::T_IS) {
$token = $this->lexer->peek(); $lookahead = $this->lexer->peek();
} }
break;
$this->lexer->resetPeek(); default:
} else { // Peek beyond the PathExpression or InputParameter.
// Peek beyond the PathExpression (or InputParameter) $token = $beyond;
$peek = $this->lexer->peek();
while ($peek['value'] === '.') { while ($token['value'] === '.') {
$this->lexer->peek(); $this->lexer->peek();
$peek = $this->lexer->peek();
}
// Also peek beyond a NOT if there is one $token = $this->lexer->peek();
if ($peek['type'] === Lexer::T_NOT) { }
$peek = $this->lexer->peek();
}
$token = $peek; // Also peek beyond a NOT if there is one.
if ($token['type'] === Lexer::T_NOT) {
$token = $this->lexer->peek();
}
// We need to go even further in case of IS (differenciate between NULL and EMPTY) // We need to go even further in case of IS (differenciate between NULL and EMPTY)
$lookahead = $this->lexer->peek();
// Also peek beyond a NOT if there is one
if ($lookahead['type'] === Lexer::T_NOT) {
$lookahead = $this->lexer->peek(); $lookahead = $this->lexer->peek();
}
$this->lexer->resetPeek();
} }
// Also peek beyond a NOT if there is one.
if ($lookahead['type'] === Lexer::T_NOT) {
$lookahead = $this->lexer->peek();
}
$this->lexer->resetPeek();
} }
switch ($token['type']) { if ($token['type'] === Lexer::T_BETWEEN) {
case Lexer::T_BETWEEN: return $this->BetweenExpression();
return $this->BetweenExpression();
case Lexer::T_LIKE:
return $this->LikeExpression();
case Lexer::T_IN:
return $this->InExpression();
case Lexer::T_INSTANCE:
return $this->InstanceOfExpression();
case Lexer::T_IS:
if ($lookahead['type'] == Lexer::T_NULL) {
return $this->NullComparisonExpression();
}
return $this->EmptyCollectionComparisonExpression();
case Lexer::T_MEMBER:
return $this->CollectionMemberExpression();
default:
return $this->ComparisonExpression();
} }
if ($token['type'] === Lexer::T_LIKE) {
return $this->LikeExpression();
}
if ($token['type'] === Lexer::T_IN) {
return $this->InExpression();
}
if ($token['type'] === Lexer::T_INSTANCE) {
return $this->InstanceOfExpression();
}
if ($token['type'] === Lexer::T_MEMBER) {
return $this->CollectionMemberExpression();
}
if ($token['type'] === Lexer::T_IS && $lookahead['type'] === Lexer::T_NULL) {
return $this->NullComparisonExpression();
}
if ($token['type'] === Lexer::T_IS && $lookahead['type'] === Lexer::T_EMPTY) {
return $this->EmptyCollectionComparisonExpression();
}
return $this->ComparisonExpression();
} }
/** /**
@ -3085,24 +3101,43 @@ class Parser
} }
/** /**
* NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL" * NullComparisonExpression ::= InputParameter | NullIfExpression | CoalesceExpression | SingleValuedPathExpression "IS" ["NOT"] "NULL"
* *
* @return \Doctrine\ORM\Query\AST\NullComparisonExpression * @return \Doctrine\ORM\Query\AST\NullComparisonExpression
*/ */
public function NullComparisonExpression() public function NullComparisonExpression()
{ {
if ($this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { switch (true) {
$this->match(Lexer::T_INPUT_PARAMETER); case $this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER):
$expr = new AST\InputParameter($this->lexer->token['value']); $this->match(Lexer::T_INPUT_PARAMETER);
} else {
$expr = $this->SingleValuedPathExpression(); $expr = new AST\InputParameter($this->lexer->token['value']);
break;
case $this->lexer->isNextToken(Lexer::T_NULLIF):
$expr = $this->NullIfExpression();
break;
case $this->lexer->isNextToken(Lexer::T_COALESCE):
$expr = $this->CoalesceExpression();
break;
case $this->isFunction():
$expr = $this->FunctionDeclaration();
break;
default:
$expr = $this->SingleValuedPathExpression();
break;
} }
$nullCompExpr = new AST\NullComparisonExpression($expr); $nullCompExpr = new AST\NullComparisonExpression($expr);
$this->match(Lexer::T_IS); $this->match(Lexer::T_IS);
if ($this->lexer->isNextToken(Lexer::T_NOT)) { if ($this->lexer->isNextToken(Lexer::T_NOT)) {
$this->match(Lexer::T_NOT); $this->match(Lexer::T_NOT);
$nullCompExpr->not = true; $nullCompExpr->not = true;
} }

View File

@ -1874,20 +1874,16 @@ class SqlWalker implements TreeWalker
*/ */
public function walkNullComparisonExpression($nullCompExpr) public function walkNullComparisonExpression($nullCompExpr)
{ {
$sql = ''; $expression = $nullCompExpr->expression;
$innerExpr = $nullCompExpr->expression; $comparison = ' IS' . ($nullCompExpr->not ? ' NOT' : '') . ' NULL';
if ($innerExpr instanceof AST\InputParameter) { if ($expression instanceof AST\InputParameter) {
$dqlParamKey = $innerExpr->name; $this->parserResult->addParameterMapping($expression->name, $this->sqlParamIndex++);
$this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++);
$sql .= ' ?'; return '?' . $comparison;
} else {
$sql .= $this->walkPathExpression($innerExpr);
} }
$sql .= ' IS' . ($nullCompExpr->not ? ' NOT' : '') . ' NULL'; return $expression->dispatch($this) . $comparison;
return $sql;
} }
/** /**

View File

@ -1654,6 +1654,47 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
} }
/**
* @group DDC-2234
*/
public function testWhereFunctionIsNullComparisonExpression()
{
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE IDENTITY(u.email) IS NULL",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.email_id IS NULL"
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE NULLIF(u.name, 'FabioBatSilva') IS NULL AND IDENTITY(u.email) IS NOT NULL",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE NULLIF(c0_.name, 'FabioBatSilva') IS NULL AND c0_.email_id IS NOT NULL"
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE IDENTITY(u.email) IS NOT NULL",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.email_id IS NOT NULL"
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE NULLIF(u.name, 'FabioBatSilva') IS NOT NULL",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE NULLIF(c0_.name, 'FabioBatSilva') IS NOT NULL"
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE COALESCE(u.name, u.id) IS NOT NULL",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE COALESCE(c0_.name, c0_.id) IS NOT NULL"
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE COALESCE(u.id, IDENTITY(u.email)) IS NOT NULL",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE COALESCE(c0_.id, c0_.email_id) IS NOT NULL"
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE COALESCE(IDENTITY(u.email), NULLIF(u.name, 'FabioBatSilva')) IS NOT NULL",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE COALESCE(c0_.email_id, NULLIF(c0_.name, 'FabioBatSilva')) IS NOT NULL"
);
}
public function testCustomTypeValueSql() public function testCustomTypeValueSql()
{ {
if (DBALType::hasType('negative_to_positive')) { if (DBALType::hasType('negative_to_positive')) {