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
* FALSE is returned.
*
* @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)
{
......@@ -404,7 +404,7 @@ abstract class AbstractQuery
* iterated over the result.
*
* @param array $params The query parameters.
* @param integer $hydrationMode The hydratio mode to use.
* @param integer $hydrationMode The hydration mode to use.
* @return IterableResult
*/
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
......
......@@ -26,9 +26,10 @@ namespace Doctrine\ORM\Query\AST;
*/
class PathExpression extends Node
{
const TYPE_COLLECTION_VALUED_ASSOCIATION = 1;
const TYPE_SINGLE_VALUED_ASSOCIATION = 2;
const TYPE_STATE_FIELD = 4;
const TYPE_SINGLE_VALUED_PATH_EXPRESSION = 1;
const TYPE_COLLECTION_VALUED_ASSOCIATION = 2;
const TYPE_SINGLE_VALUED_ASSOCIATION = 4;
const TYPE_STATE_FIELD = 8;
private $_type;
private $_identificationVariable;
......@@ -51,6 +52,11 @@ class PathExpression extends Node
return $this->_parts;
}
public function setType($type)
{
$this->_type = $type;
}
public function getType()
{
return $this->_type;
......
......@@ -415,6 +415,10 @@ class Parser
case AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION:
$this->_validateCollectionValuedAssociationPathExpression($expr);
break;
case AST\PathExpression::TYPE_SINGLE_VALUED_PATH_EXPRESSION:
$this->_validateSingleValuedPathExpression($expr);
break;
default:
$this->semanticalError('Encountered invalid PathExpression.');
......@@ -660,7 +664,8 @@ class Parser
// Deny hydration of partial objects if doctrine.forcePartialLoad query hint not defined
if (
$this->_query->getHydrationMode() == Query::HYDRATE_OBJECT &&
! $this->_em->getConfiguration()->getAllowPartialObjects()
! $this->_em->getConfiguration()->getAllowPartialObjects() &&
! $this->_query->getHint('doctrine.forcePartialLoad')
) {
throw DoctrineException::partialObjectsAreDangerous();
}
......@@ -891,9 +896,10 @@ class Parser
{
$pathExpr = $this->PathExpression(AST\PathExpression::TYPE_STATE_FIELD);
if (count($pathExpr->getParts()) > 1) {
$this->syntaxError('SimpleStateFieldPathExpression');
}
// @TODO It seems PathExpression already checks for the minimum amount of parts
// if (count($pathExpr->getParts()) > 1) {
// $this->syntaxError('SimpleStateFieldPathExpression');
// }
if ( ! empty($this->_deferredPathExpressionStacks)) {
$exprStack = array_pop($this->_deferredPathExpressionStacks);
......@@ -947,6 +953,26 @@ class Parser
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
......@@ -982,7 +1008,7 @@ class Parser
/**
* 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
*/
......@@ -1010,6 +1036,22 @@ class Parser
* @param 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'];
$stateFieldSeen = false;
......@@ -1027,10 +1069,16 @@ class Parser
$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) {
$this->semanticalError('Invalid StateFieldPathExpression. Must end in a state field.');
}
return $stateFieldSeen;
}
/**
......@@ -1042,8 +1090,7 @@ class Parser
*/
public function PathExpression($type)
{
$this->match(Lexer::T_IDENTIFIER);
$identificationVariable = $this->_lexer->token['value'];
$identificationVariable = $this->IdentificationVariable();
$parts = array();
......@@ -1081,15 +1128,11 @@ class Parser
return new AST\InputParameter($this->_lexer->token['value']);
}
$this->match(Lexer::T_IDENTIFIER);
return $this->_lexer->token['value'];
return $this->IdentificationVariable();
}
/**
* NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"
*
* @todo Implementation incomplete for SingleValuedPathExpression.
*/
public function NullComparisonExpression()
{
......@@ -1097,8 +1140,7 @@ class Parser
$this->match(Lexer::T_INPUT_PARAMETER);
$expr = new AST\InputParameter($this->_lexer->token['value']);
} else {
//TODO: Support SingleValuedAssociationPathExpression
$expr = $this->StateFieldPathExpression();
$expr = $this->SingleValuedPathExpression();
}
$nullCompExpr = new AST\NullComparisonExpression($expr);
......@@ -1117,9 +1159,7 @@ class Parser
/**
* AggregateExpression ::=
* ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" |
* "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedAssociationPathExpression | StateFieldPathExpression) ")"
*
* @todo Implementation incomplete. Support for SingleValuedAssociationPathExpression.
* "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedPathExpression) ")"
*/
public function AggregateExpression()
{
......@@ -1136,8 +1176,7 @@ class Parser
$isDistinct = true;
}
//TODO: Support SingleValuedAssociationPathExpression
$pathExp = $this->StateFieldPathExpression();
$pathExp = $this->SingleValuedPathExpression();
$this->match(')');
} else {
if ($this->_lexer->isNextToken(Lexer::T_AVG)) {
......@@ -1878,11 +1917,9 @@ class Parser
}
/**
* ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")"
* ArithmeticPrimary ::= SingleValuedPathExpression | Literal | "(" SimpleArithmeticExpression ")"
* | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings
* | FunctionsReturningDatetime | IdentificationVariable | SingleValuedAssociationPathExpression
*
* @todo IdentificationVariable | SingleValuedAssociationPathExpression
* | FunctionsReturningDatetime | IdentificationVariable
*/
public function ArithmeticPrimary()
{
......@@ -1903,14 +1940,10 @@ class Parser
}
if ($peek['value'] == '.') {
//TODO: SingleValuedAssociationPathExpression
return $this->StateFieldPathExpression();
return $this->SingleValuedPathExpression();
}
$identificationVariable = $this->_lexer->lookahead['value'];
$this->match($identificationVariable);
return $identificationVariable;
return $this->IdentificationVariable();
case Lexer::T_INPUT_PARAMETER:
$this->match($this->_lexer->lookahead['value']);
......
......@@ -1065,7 +1065,7 @@ class SqlWalker implements TreeWalker
if ($leftExpr instanceof AST\Node) {
$sql .= $leftExpr->dispatch($this);
} else {
$sql .= $leftExpr; //TODO: quote()
$sql .= $this->_conn->quote($leftExpr);
}
$sql .= ' ' . $compExpr->getOperator() . ' ';
......@@ -1073,7 +1073,7 @@ class SqlWalker implements TreeWalker
if ($rightExpr instanceof AST\Node) {
$sql .= $rightExpr->dispatch($this);
} else {
$sql .= $rightExpr; //TODO: quote()
$sql .= $this->_conn->quote($rightExpr);
}
return $sql;
......
......@@ -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->setDql($dql);
foreach ($hints as $key => $value) {
$query->setHint($key, $value);
}
$parser = new \Doctrine\ORM\Query\Parser($query);
$parser->setSqlTreeWalker(new \Doctrine\Tests\Mocks\MockTreeWalker);
......@@ -339,8 +344,10 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
{
$oldValue = $this->_em->getConfiguration()->getAllowPartialObjects();
$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);
}
......
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