Commit 227667c9 authored by guilhermeblanco's avatar guilhermeblanco

[2.0] Changes in DQL grammar for optimization purposes. Implemented new DQL...

[2.0] Changes in DQL grammar for optimization purposes. Implemented new DQL grammar rules and did a couple of TODOs
parent 3747365b
...@@ -392,7 +392,7 @@ abstract class AbstractQuery ...@@ -392,7 +392,7 @@ abstract class AbstractQuery
* FALSE is returned. * FALSE is returned.
* *
* @param string $name The name of the hint. * @param string $name The name of the hint.
* @return mixed The value of the hint or FALSe, if the hint name is not recognized. * @return mixed The value of the hint or FALSE, if the hint name is not recognized.
*/ */
public function getHint($name) public function getHint($name)
{ {
...@@ -404,7 +404,7 @@ abstract class AbstractQuery ...@@ -404,7 +404,7 @@ abstract class AbstractQuery
* iterated over the result. * iterated over the result.
* *
* @param array $params The query parameters. * @param array $params The query parameters.
* @param integer $hydrationMode The hydratio mode to use. * @param integer $hydrationMode The hydration mode to use.
* @return IterableResult * @return IterableResult
*/ */
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT) public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
......
...@@ -26,9 +26,10 @@ namespace Doctrine\ORM\Query\AST; ...@@ -26,9 +26,10 @@ namespace Doctrine\ORM\Query\AST;
*/ */
class PathExpression extends Node class PathExpression extends Node
{ {
const TYPE_COLLECTION_VALUED_ASSOCIATION = 1; const TYPE_SINGLE_VALUED_PATH_EXPRESSION = 1;
const TYPE_SINGLE_VALUED_ASSOCIATION = 2; const TYPE_COLLECTION_VALUED_ASSOCIATION = 2;
const TYPE_STATE_FIELD = 4; const TYPE_SINGLE_VALUED_ASSOCIATION = 4;
const TYPE_STATE_FIELD = 8;
private $_type; private $_type;
private $_identificationVariable; private $_identificationVariable;
...@@ -51,6 +52,11 @@ class PathExpression extends Node ...@@ -51,6 +52,11 @@ class PathExpression extends Node
return $this->_parts; return $this->_parts;
} }
public function setType($type)
{
$this->_type = $type;
}
public function getType() public function getType()
{ {
return $this->_type; return $this->_type;
......
...@@ -415,6 +415,10 @@ class Parser ...@@ -415,6 +415,10 @@ class Parser
case AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION: case AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION:
$this->_validateCollectionValuedAssociationPathExpression($expr); $this->_validateCollectionValuedAssociationPathExpression($expr);
break; break;
case AST\PathExpression::TYPE_SINGLE_VALUED_PATH_EXPRESSION:
$this->_validateSingleValuedPathExpression($expr);
break;
default: default:
$this->semanticalError('Encountered invalid PathExpression.'); $this->semanticalError('Encountered invalid PathExpression.');
...@@ -660,7 +664,8 @@ class Parser ...@@ -660,7 +664,8 @@ class Parser
// Deny hydration of partial objects if doctrine.forcePartialLoad query hint not defined // Deny hydration of partial objects if doctrine.forcePartialLoad query hint not defined
if ( if (
$this->_query->getHydrationMode() == Query::HYDRATE_OBJECT && $this->_query->getHydrationMode() == Query::HYDRATE_OBJECT &&
! $this->_em->getConfiguration()->getAllowPartialObjects() ! $this->_em->getConfiguration()->getAllowPartialObjects() &&
! $this->_query->getHint('doctrine.forcePartialLoad')
) { ) {
throw DoctrineException::partialObjectsAreDangerous(); throw DoctrineException::partialObjectsAreDangerous();
} }
...@@ -891,9 +896,10 @@ class Parser ...@@ -891,9 +896,10 @@ class Parser
{ {
$pathExpr = $this->PathExpression(AST\PathExpression::TYPE_STATE_FIELD); $pathExpr = $this->PathExpression(AST\PathExpression::TYPE_STATE_FIELD);
if (count($pathExpr->getParts()) > 1) { // @TODO It seems PathExpression already checks for the minimum amount of parts
$this->syntaxError('SimpleStateFieldPathExpression'); // if (count($pathExpr->getParts()) > 1) {
} // $this->syntaxError('SimpleStateFieldPathExpression');
// }
if ( ! empty($this->_deferredPathExpressionStacks)) { if ( ! empty($this->_deferredPathExpressionStacks)) {
$exprStack = array_pop($this->_deferredPathExpressionStacks); $exprStack = array_pop($this->_deferredPathExpressionStacks);
...@@ -947,6 +953,26 @@ class Parser ...@@ -947,6 +953,26 @@ class Parser
return $pathExpr; return $pathExpr;
} }
/**
* SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
*/
public function SingleValuedPathExpression()
{
$pathExpr = $this->PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_PATH_EXPRESSION);
if ( ! empty($this->_deferredPathExpressionStacks)) {
$exprStack = array_pop($this->_deferredPathExpressionStacks);
$exprStack[] = $pathExpr;
array_push($this->_deferredPathExpressionStacks, $exprStack);
return $pathExpr;
}
$this->_validateSingleValuedPathExpression($pathExpr);
return $pathExpr;
}
/** /**
* Validates that the given <tt>PathExpression</tt> is a semantically correct * Validates that the given <tt>PathExpression</tt> is a semantically correct
...@@ -982,7 +1008,7 @@ class Parser ...@@ -982,7 +1008,7 @@ class Parser
/** /**
* Validates that the given <tt>PathExpression</tt> is a semantically correct * Validates that the given <tt>PathExpression</tt> is a semantically correct
* SingleValuedPathExpression as specified in the grammar. * SingleValuedAssociationPathExpression as specified in the grammar.
* *
* @param PathExpression $pathExpression * @param PathExpression $pathExpression
*/ */
...@@ -1010,6 +1036,22 @@ class Parser ...@@ -1010,6 +1036,22 @@ class Parser
* @param PathExpression $pathExpression * @param PathExpression $pathExpression
*/ */
private function _validateStateFieldPathExpression(AST\PathExpression $pathExpression) private function _validateStateFieldPathExpression(AST\PathExpression $pathExpression)
{
$stateFieldSeen = $this->_validateSingleValuedPathExpression($pathExpression);
if ( ! $stateFieldSeen) {
$this->semanticalError('Invalid StateFieldPathExpression. Must end in a state field.');
}
}
/**
* Validates that the given <tt>PathExpression</tt> is a semantically correct
* SingleValuedPathExpression as specified in the grammar.
*
* @param PathExpression $pathExpression
* @return boolean
*/
private function _validateSingleValuedPathExpression(AST\PathExpression $pathExpression)
{ {
$class = $this->_queryComponents[$pathExpression->getIdentificationVariable()]['metadata']; $class = $this->_queryComponents[$pathExpression->getIdentificationVariable()]['metadata'];
$stateFieldSeen = false; $stateFieldSeen = false;
...@@ -1027,10 +1069,16 @@ class Parser ...@@ -1027,10 +1069,16 @@ class Parser
$this->semanticalError('SingleValuedAssociationField or StateField expected.'); $this->semanticalError('SingleValuedAssociationField or StateField expected.');
} }
} }
// We need to force the type in PathExpression since SingleValuedPathExpression is in a
// state of recognition of what's is the dealed type (StateField or SingleValuedAssociation)
$pathExpression->setType(
($stateFieldSeen)
? AST\PathExpression::TYPE_STATE_FIELD
: AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION
);
if ( ! $stateFieldSeen) { return $stateFieldSeen;
$this->semanticalError('Invalid StateFieldPathExpression. Must end in a state field.');
}
} }
/** /**
...@@ -1042,8 +1090,7 @@ class Parser ...@@ -1042,8 +1090,7 @@ class Parser
*/ */
public function PathExpression($type) public function PathExpression($type)
{ {
$this->match(Lexer::T_IDENTIFIER); $identificationVariable = $this->IdentificationVariable();
$identificationVariable = $this->_lexer->token['value'];
$parts = array(); $parts = array();
...@@ -1081,15 +1128,11 @@ class Parser ...@@ -1081,15 +1128,11 @@ class Parser
return new AST\InputParameter($this->_lexer->token['value']); return new AST\InputParameter($this->_lexer->token['value']);
} }
$this->match(Lexer::T_IDENTIFIER); return $this->IdentificationVariable();
return $this->_lexer->token['value'];
} }
/** /**
* NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL" * NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"
*
* @todo Implementation incomplete for SingleValuedPathExpression.
*/ */
public function NullComparisonExpression() public function NullComparisonExpression()
{ {
...@@ -1097,8 +1140,7 @@ class Parser ...@@ -1097,8 +1140,7 @@ class Parser
$this->match(Lexer::T_INPUT_PARAMETER); $this->match(Lexer::T_INPUT_PARAMETER);
$expr = new AST\InputParameter($this->_lexer->token['value']); $expr = new AST\InputParameter($this->_lexer->token['value']);
} else { } else {
//TODO: Support SingleValuedAssociationPathExpression $expr = $this->SingleValuedPathExpression();
$expr = $this->StateFieldPathExpression();
} }
$nullCompExpr = new AST\NullComparisonExpression($expr); $nullCompExpr = new AST\NullComparisonExpression($expr);
...@@ -1117,9 +1159,7 @@ class Parser ...@@ -1117,9 +1159,7 @@ class Parser
/** /**
* AggregateExpression ::= * AggregateExpression ::=
* ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" | * ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" |
* "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedAssociationPathExpression | StateFieldPathExpression) ")" * "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedPathExpression) ")"
*
* @todo Implementation incomplete. Support for SingleValuedAssociationPathExpression.
*/ */
public function AggregateExpression() public function AggregateExpression()
{ {
...@@ -1136,8 +1176,7 @@ class Parser ...@@ -1136,8 +1176,7 @@ class Parser
$isDistinct = true; $isDistinct = true;
} }
//TODO: Support SingleValuedAssociationPathExpression $pathExp = $this->SingleValuedPathExpression();
$pathExp = $this->StateFieldPathExpression();
$this->match(')'); $this->match(')');
} else { } else {
if ($this->_lexer->isNextToken(Lexer::T_AVG)) { if ($this->_lexer->isNextToken(Lexer::T_AVG)) {
...@@ -1878,11 +1917,9 @@ class Parser ...@@ -1878,11 +1917,9 @@ class Parser
} }
/** /**
* ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" * ArithmeticPrimary ::= SingleValuedPathExpression | Literal | "(" SimpleArithmeticExpression ")"
* | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings * | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings
* | FunctionsReturningDatetime | IdentificationVariable | SingleValuedAssociationPathExpression * | FunctionsReturningDatetime | IdentificationVariable
*
* @todo IdentificationVariable | SingleValuedAssociationPathExpression
*/ */
public function ArithmeticPrimary() public function ArithmeticPrimary()
{ {
...@@ -1903,14 +1940,10 @@ class Parser ...@@ -1903,14 +1940,10 @@ class Parser
} }
if ($peek['value'] == '.') { if ($peek['value'] == '.') {
//TODO: SingleValuedAssociationPathExpression return $this->SingleValuedPathExpression();
return $this->StateFieldPathExpression();
} }
$identificationVariable = $this->_lexer->lookahead['value']; return $this->IdentificationVariable();
$this->match($identificationVariable);
return $identificationVariable;
case Lexer::T_INPUT_PARAMETER: case Lexer::T_INPUT_PARAMETER:
$this->match($this->_lexer->lookahead['value']); $this->match($this->_lexer->lookahead['value']);
......
...@@ -1065,7 +1065,7 @@ class SqlWalker implements TreeWalker ...@@ -1065,7 +1065,7 @@ class SqlWalker implements TreeWalker
if ($leftExpr instanceof AST\Node) { if ($leftExpr instanceof AST\Node) {
$sql .= $leftExpr->dispatch($this); $sql .= $leftExpr->dispatch($this);
} else { } else {
$sql .= $leftExpr; //TODO: quote() $sql .= $this->_conn->quote($leftExpr);
} }
$sql .= ' ' . $compExpr->getOperator() . ' '; $sql .= ' ' . $compExpr->getOperator() . ' ';
...@@ -1073,7 +1073,7 @@ class SqlWalker implements TreeWalker ...@@ -1073,7 +1073,7 @@ class SqlWalker implements TreeWalker
if ($rightExpr instanceof AST\Node) { if ($rightExpr instanceof AST\Node) {
$sql .= $rightExpr->dispatch($this); $sql .= $rightExpr->dispatch($this);
} else { } else {
$sql .= $rightExpr; //TODO: quote() $sql .= $this->_conn->quote($rightExpr);
} }
return $sql; return $sql;
......
...@@ -37,10 +37,15 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase ...@@ -37,10 +37,15 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
} }
} }
public function parseDql($dql) public function parseDql($dql, $hints = array())
{ {
$query = $this->_em->createQuery($dql); $query = $this->_em->createQuery($dql);
$query->setDql($dql); $query->setDql($dql);
foreach ($hints as $key => $value) {
$query->setHint($key, $value);
}
$parser = new \Doctrine\ORM\Query\Parser($query); $parser = new \Doctrine\ORM\Query\Parser($query);
$parser->setSqlTreeWalker(new \Doctrine\Tests\Mocks\MockTreeWalker); $parser->setSqlTreeWalker(new \Doctrine\Tests\Mocks\MockTreeWalker);
...@@ -339,8 +344,10 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase ...@@ -339,8 +344,10 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
{ {
$oldValue = $this->_em->getConfiguration()->getAllowPartialObjects(); $oldValue = $this->_em->getConfiguration()->getAllowPartialObjects();
$this->_em->getConfiguration()->setAllowPartialObjects(false); $this->_em->getConfiguration()->setAllowPartialObjects(false);
$this->parseDql('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u'); $this->parseDql('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u', array(
'doctrine.forcePartialLoad' => false
));
$this->_em->getConfiguration()->setAllowPartialObjects($oldValue); $this->_em->getConfiguration()->setAllowPartialObjects($oldValue);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment