1
0
mirror of synced 2025-02-06 15:29:26 +03:00

Improved code readability. Improved performance.

This commit is contained in:
Guilherme Blanco 2011-11-30 09:57:54 -05:00
parent 356f5874bf
commit 5b73f1bd82
5 changed files with 250 additions and 214 deletions

View File

@ -23,8 +23,9 @@ namespace Doctrine\ORM\Internal;
* The CommitOrderCalculator is used by the UnitOfWork to sort out the * The CommitOrderCalculator is used by the UnitOfWork to sort out the
* correct order in which changes to entities need to be persisted. * correct order in which changes to entities need to be persisted.
* *
* @since 2.0 * @since 2.0
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/ */
class CommitOrderCalculator class CommitOrderCalculator
{ {
@ -60,10 +61,9 @@ class CommitOrderCalculator
{ {
// Check whether we need to do anything. 0 or 1 node is easy. // Check whether we need to do anything. 0 or 1 node is easy.
$nodeCount = count($this->_classes); $nodeCount = count($this->_classes);
if ($nodeCount == 0) {
return array(); if ($nodeCount <= 1) {
} else if ($nodeCount == 1) { return ($nodeCount == 1) ? array_values($this->_classes) : array();
return array_values($this->_classes);
} }
// Init // Init

View File

@ -36,11 +36,6 @@ use PDO,
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com> * @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
* *
* @internal Highly performance-sensitive code. * @internal Highly performance-sensitive code.
*
* @todo General behavior is "wrong" if you define an alias to selected IdentificationVariable.
* Example: SELECT u AS user FROM User u
* The result should contains an array where each array index is an array: array('user' => [User object])
* Problem must be solved somehow by removing the isMixed in ResultSetMapping
*/ */
class ObjectHydrator extends AbstractHydrator class ObjectHydrator extends AbstractHydrator
{ {

View File

@ -164,7 +164,7 @@ final class PersistentCollection implements Collection
// If _backRefFieldName is set and its a one-to-many association, // If _backRefFieldName is set and its a one-to-many association,
// we need to set the back reference. // we need to set the back reference.
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) { if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner // Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]->setValue( $this->typeClass->reflFields[$this->backRefFieldName]->setValue(
$element, $this->owner $element, $this->owner
@ -189,7 +189,7 @@ final class PersistentCollection implements Collection
// If _backRefFieldName is set, then the association is bidirectional // If _backRefFieldName is set, then the association is bidirectional
// and we need to set the back reference. // and we need to set the back reference.
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) { if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner // Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]->setValue( $this->typeClass->reflFields[$this->backRefFieldName]->setValue(
$element, $this->owner $element, $this->owner
@ -304,7 +304,7 @@ final class PersistentCollection implements Collection
if ($this->association !== null && if ($this->association !== null &&
$this->association['isOwningSide'] && $this->association['isOwningSide'] &&
$this->association['type'] == ClassMetadata::MANY_TO_MANY && $this->association['type'] === ClassMetadata::MANY_TO_MANY &&
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) { $this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner); $this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
} }
@ -425,7 +425,7 @@ final class PersistentCollection implements Collection
$this->changed(); $this->changed();
if ($this->association !== null && if ($this->association !== null &&
$this->association['type'] == ClassMetadata::ONE_TO_MANY && $this->association['type'] === ClassMetadata::ONE_TO_MANY &&
$this->association['orphanRemoval']) { $this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element); $this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
} }
@ -448,7 +448,7 @@ final class PersistentCollection implements Collection
*/ */
public function contains($element) public function contains($element)
{ {
if ( ! $this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $this->coll->contains($element) || $persister->contains($this, $element); return $this->coll->contains($element) || $persister->contains($this, $element);
@ -514,7 +514,7 @@ final class PersistentCollection implements Collection
*/ */
public function count() public function count()
{ {
if ( ! $this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $persister->count($this) + ($this->isDirty ? $this->coll->count() : 0); return $persister->count($this) + ($this->isDirty ? $this->coll->count() : 0);
@ -630,7 +630,7 @@ final class PersistentCollection implements Collection
$uow = $this->em->getUnitOfWork(); $uow = $this->em->getUnitOfWork();
if ($this->association['type'] == ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) { if ($this->association['type'] === ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
// we need to initialize here, as orphan removal acts like implicit cascadeRemove, // we need to initialize here, as orphan removal acts like implicit cascadeRemove,
// hence for event listeners we need the objects in memory. // hence for event listeners we need the objects in memory.
$this->initialize(); $this->initialize();

View File

@ -49,7 +49,7 @@ class Lexer extends \Doctrine\Common\Lexer
const T_PLUS = 17; const T_PLUS = 17;
const T_OPEN_CURLY_BRACE = 18; const T_OPEN_CURLY_BRACE = 18;
const T_CLOSE_CURLY_BRACE = 19; const T_CLOSE_CURLY_BRACE = 19;
// All tokens that are also identifiers should be >= 100 // All tokens that are also identifiers should be >= 100
const T_IDENTIFIER = 100; const T_IDENTIFIER = 100;
const T_ALL = 101; const T_ALL = 101;
@ -133,7 +133,7 @@ class Lexer extends \Doctrine\Common\Lexer
'\?[0-9]*|:[a-z]{1}[a-z0-9_]{0,}' '\?[0-9]*|:[a-z]{1}[a-z0-9_]{0,}'
); );
} }
/** /**
* @inheritdoc * @inheritdoc
*/ */
@ -149,50 +149,58 @@ class Lexer extends \Doctrine\Common\Lexer
{ {
$type = self::T_NONE; $type = self::T_NONE;
// Recognizing numeric values switch (true) {
if (is_numeric($value)) { // Recognize numeric values
return (strpos($value, '.') !== false || stripos($value, 'e') !== false) case (is_numeric($value)):
? self::T_FLOAT : self::T_INTEGER; if (strpos($value, '.') !== false || stripos($value, 'e') !== false) {
} return self::T_FLOAT;
// Differentiate between quoted names, identifiers, input parameters and symbols
if ($value[0] === "'") {
$value = str_replace("''", "'", substr($value, 1, strlen($value) - 2));
return self::T_STRING;
} else if (ctype_alpha($value[0]) || $value[0] === '_') {
$name = 'Doctrine\ORM\Query\Lexer::T_' . strtoupper($value);
if (defined($name)) {
$type = constant($name);
if ($type > 100) {
return $type;
} }
}
return self::T_IDENTIFIER; return self::T_INTEGER;
} else if ($value[0] === '?' || $value[0] === ':') {
return self::T_INPUT_PARAMETER; // Recognize quoted strings
} else { case ($value[0] === "'"):
switch ($value) { $value = str_replace("''", "'", substr($value, 1, strlen($value) - 2));
case '.': return self::T_DOT;
case ',': return self::T_COMMA; return self::T_STRING;
case '(': return self::T_OPEN_PARENTHESIS;
case ')': return self::T_CLOSE_PARENTHESIS; // Recognize identifiers
case '=': return self::T_EQUALS; case (ctype_alpha($value[0]) || $value[0] === '_'):
case '>': return self::T_GREATER_THAN; $name = 'Doctrine\ORM\Query\Lexer::T_' . strtoupper($value);
case '<': return self::T_LOWER_THAN;
case '+': return self::T_PLUS; if (defined($name)) {
case '-': return self::T_MINUS; $type = constant($name);
case '*': return self::T_MULTIPLY;
case '/': return self::T_DIVIDE; if ($type > 100) {
case '!': return self::T_NEGATE; return $type;
case '{': return self::T_OPEN_CURLY_BRACE; }
case '}': return self::T_CLOSE_CURLY_BRACE; }
default:
// Do nothing return self::T_IDENTIFIER;
break;
} // Recognize input parameters
case ($value[0] === '?' || $value[0] === ':'):
return self::T_INPUT_PARAMETER;
// Recognize symbols
case ($value === '.'): return self::T_DOT;
case ($value === ','): return self::T_COMMA;
case ($value === '('): return self::T_OPEN_PARENTHESIS;
case ($value === ')'): return self::T_CLOSE_PARENTHESIS;
case ($value === '='): return self::T_EQUALS;
case ($value === '>'): return self::T_GREATER_THAN;
case ($value === '<'): return self::T_LOWER_THAN;
case ($value === '+'): return self::T_PLUS;
case ($value === '-'): return self::T_MINUS;
case ($value === '*'): return self::T_MULTIPLY;
case ($value === '/'): return self::T_DIVIDE;
case ($value === '!'): return self::T_NEGATE;
case ($value === '{'): return self::T_OPEN_CURLY_BRACE;
case ($value === '}'): return self::T_CLOSE_CURLY_BRACE;
// Default
default:
// Do nothing
} }
return $type; return $type;

View File

@ -677,13 +677,10 @@ class Parser
} }
// Build the error message // Build the error message
$semanticalError = 'Invalid PathExpression. '; $semanticalError = 'Invalid PathExpression. ';
$semanticalError .= (count($expectedStringTypes) == 1)
if (count($expectedStringTypes) == 1) { ? 'Must be a ' . $expectedStringTypes[0] . '.'
$semanticalError .= 'Must be a ' . $expectedStringTypes[0] . '.'; : implode(' or ', $expectedStringTypes) . ' expected.';
} else {
$semanticalError .= implode(' or ', $expectedStringTypes) . ' expected.';
}
$this->semanticalError($semanticalError, $deferredItem['token']); $this->semanticalError($semanticalError, $deferredItem['token']);
} }
@ -1866,53 +1863,78 @@ class Parser
$expression = null; $expression = null;
$identVariable = null; $identVariable = null;
$peek = $this->_lexer->glimpse(); $peek = $this->_lexer->glimpse();
$lookaheadType = $this->_lexer->lookahead['type'];
if ($this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER && $peek['type'] === Lexer::T_DOT) { switch (true) {
// ScalarExpression (u.name) // ScalarExpression (u.name)
$expression = $this->ScalarExpression(); case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] === Lexer::T_DOT):
} else if ($this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER && $peek['type'] !== Lexer::T_OPEN_PARENTHESIS) {
// IdentificationVariable (u)
$expression = $identVariable = $this->IdentificationVariable();
} else if (in_array($this->_lexer->lookahead['type'], array(Lexer::T_CASE, Lexer::T_COALESCE, Lexer::T_NULLIF))) {
// CaseExpression (CASE ... or NULLIF(...) or COALESCE(...))
$expression = $this->CaseExpression();
} else if ($this->_isFunction()) {
// DQL Function (SUM(u.value) or SUM(u.value) + 1)
$this->_lexer->peek(); // "("
$lookaheadType = $this->_lexer->lookahead['type'];
$beyond = $this->_peekBeyondClosingParenthesis();
if ($this->_isMathOperator($beyond)) {
// SUM(u.id) + COUNT(u.id)
$expression = $this->ScalarExpression(); $expression = $this->ScalarExpression();
} else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { break;
// COUNT(u.id)
$expression = $this->AggregateExpression(); // IdentificationVariable (u)
} else { case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] !== Lexer::T_OPEN_PARENTHESIS):
// SUM(u.id) $expression = $identVariable = $this->IdentificationVariable();
$expression = $this->FunctionDeclaration(); break;
}
} else if ($this->_lexer->lookahead['type'] === Lexer::T_PARTIAL) { // CaseExpression (CASE ... or NULLIF(...) or COALESCE(...))
case ($lookaheadType === Lexer::T_CASE):
case ($lookaheadType === Lexer::T_COALESCE):
case ($lookaheadType === Lexer::T_NULLIF):
$expression = $this->CaseExpression();
break;
// DQL Function (SUM(u.value) or SUM(u.value) + 1)
case ($this->_isFunction()):
$this->_lexer->peek(); // "("
switch (true) {
case ($this->_isMathOperator($this->_peekBeyondClosingParenthesis())):
// SUM(u.id) + COUNT(u.id)
$expression = $this->ScalarExpression();
break;
case ($this->_isAggregateFunction($lookaheadType)):
// COUNT(u.id)
$expression = $this->AggregateExpression();
break;
default:
// IDENTITY(u)
$expression = $this->FunctionDeclaration();
break;
}
break;
// PartialObjectExpression (PARTIAL u.{id, name}) // PartialObjectExpression (PARTIAL u.{id, name})
$expression = $this->PartialObjectExpression(); case ($lookaheadType === Lexer::T_PARTIAL):
$identVariable = $expression->identificationVariable; $expression = $this->PartialObjectExpression();
} else if ($this->_lexer->lookahead['type'] === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT) { $identVariable = $expression->identificationVariable;
break;
// Subselect // Subselect
$this->match(Lexer::T_OPEN_PARENTHESIS); case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT):
$expression = $this->Subselect(); $this->match(Lexer::T_OPEN_PARENTHESIS);
$this->match(Lexer::T_CLOSE_PARENTHESIS); $expression = $this->Subselect();
} else if (in_array($this->_lexer->lookahead['type'], array(Lexer::T_OPEN_PARENTHESIS, Lexer::T_INTEGER, Lexer::T_FLOAT, Lexer::T_STRING))) { $this->match(Lexer::T_CLOSE_PARENTHESIS);
break;
// Shortcut: ScalarExpression => SimpleArithmeticExpression // Shortcut: ScalarExpression => SimpleArithmeticExpression
$expression = $this->SimpleArithmeticExpression(); case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS):
} else if (in_array($this->_lexer->lookahead['type'], array(Lexer::T_PLUS, Lexer::T_MINUS))) { case ($lookaheadType === Lexer::T_INTEGER):
// SimpleArithmeticExpression : (- u.value ) or ( + u.value ) case ($lookaheadType === Lexer::T_STRING):
$expression = $this->SimpleArithmeticExpression(); case ($lookaheadType === Lexer::T_FLOAT):
} else { // SimpleArithmeticExpression : (- u.value ) or ( + u.value )
$this->syntaxError( case ($lookaheadType === Lexer::T_MINUS):
'IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression', case ($lookaheadType === Lexer::T_PLUS):
$this->_lexer->lookahead $expression = $this->SimpleArithmeticExpression();
); break;
default:
$this->syntaxError(
'IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression',
$this->_lexer->lookahead
);
} }
// [["AS"] ["HIDDEN"] AliasResultVariable] // [["AS"] ["HIDDEN"] AliasResultVariable]
@ -1965,25 +1987,41 @@ class Parser
{ {
$peek = $this->_lexer->glimpse(); $peek = $this->_lexer->glimpse();
if ($peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) { switch ($this->_lexer->lookahead['type']) {
// SingleValuedPathExpression | IdentificationVariable case Lexer::T_IDENTIFIER:
$expression = ($peek['value'] == '.') switch (true) {
? $this->StateFieldPathExpression() case ($peek['type'] === Lexer::T_DOT):
: $this->IdentificationVariable(); $expression = $this->StateFieldPathExpression();
return new AST\SimpleSelectExpression($expression);
case ($peek['type'] !== Lexer::T_OPEN_PARENTHESIS):
$expression = $this->IdentificationVariable();
return new AST\SimpleSelectExpression($expression);
default:
// Do nothing
}
break;
case Lexer::T_OPEN_PARENTHESIS:
if ($peek['type'] !== Lexer::T_SELECT) {
// Shortcut: ScalarExpression => SimpleArithmeticExpression
$expression = $this->SimpleArithmeticExpression();
return new AST\SimpleSelectExpression($expression);
}
return new AST\SimpleSelectExpression($expression);
} else if ($this->_lexer->lookahead['value'] == '(') {
if ($peek['type'] == Lexer::T_SELECT) {
// Subselect // Subselect
$this->match(Lexer::T_OPEN_PARENTHESIS); $this->match(Lexer::T_OPEN_PARENTHESIS);
$expression = $this->Subselect(); $expression = $this->Subselect();
$this->match(Lexer::T_CLOSE_PARENTHESIS); $this->match(Lexer::T_CLOSE_PARENTHESIS);
} else {
// Shortcut: ScalarExpression => SimpleArithmeticExpression
$expression = $this->SimpleArithmeticExpression();
}
return new AST\SimpleSelectExpression($expression); return new AST\SimpleSelectExpression($expression);
default:
// Do nothing
} }
$this->_lexer->peek(); $this->_lexer->peek();
@ -2099,27 +2137,26 @@ class Parser
{ {
$condPrimary = new AST\ConditionalPrimary; $condPrimary = new AST\ConditionalPrimary;
if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) { if ( ! $this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
// Peek beyond the matching closing paranthesis ')'
$peek = $this->_peekBeyondClosingParenthesis();
if (in_array($peek['value'], array("=", "<", "<=", "<>", ">", ">=", "!=")) ||
$peek['type'] === Lexer::T_NOT ||
$peek['type'] === Lexer::T_BETWEEN ||
$peek['type'] === Lexer::T_LIKE ||
$peek['type'] === Lexer::T_IN ||
$peek['type'] === Lexer::T_IS ||
$peek['type'] === Lexer::T_EXISTS) {
$condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
} else {
$this->match(Lexer::T_OPEN_PARENTHESIS);
$condPrimary->conditionalExpression = $this->ConditionalExpression();
$this->match(Lexer::T_CLOSE_PARENTHESIS);
}
} else {
$condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression(); $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
return $condPrimary;
} }
// Peek beyond the matching closing paranthesis ')'
$peek = $this->_peekBeyondClosingParenthesis();
if (in_array($peek['value'], array("=", "<", "<=", "<>", ">", ">=", "!=")) ||
in_array($peek['type'], array(Lexer::T_NOT, Lexer::T_BETWEEN, Lexer::T_LIKE, Lexer::T_IN, Lexer::T_IS, Lexer::T_EXISTS))) {
$condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
return $condPrimary;
}
$this->match(Lexer::T_OPEN_PARENTHESIS);
$condPrimary->conditionalExpression = $this->ConditionalExpression();
$this->match(Lexer::T_CLOSE_PARENTHESIS);
return $condPrimary; return $condPrimary;
} }
@ -2132,10 +2169,10 @@ class Parser
*/ */
public function SimpleConditionalExpression() public function SimpleConditionalExpression()
{ {
$token = $this->_lexer->lookahead;
if ($this->_lexer->isNextToken(Lexer::T_NOT)) { if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
$token = $this->_lexer->glimpse(); $token = $this->_lexer->glimpse();
} else {
$token = $this->_lexer->lookahead;
} }
if ($token['type'] === Lexer::T_EXISTS) { if ($token['type'] === Lexer::T_EXISTS) {
@ -2464,9 +2501,9 @@ class Parser
} }
return $this->FunctionDeclaration(); return $this->FunctionDeclaration();
} else {
return $this->Literal();
} }
return $this->Literal();
} }
} }
@ -2498,30 +2535,46 @@ class Parser
*/ */
public function StringPrimary() public function StringPrimary()
{ {
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { $lookaheadType = $this->_lexer->lookahead['type'];
$peek = $this->_lexer->glimpse();
switch ($lookaheadType) {
case Lexer::T_IDENTIFIER:
$peek = $this->_lexer->glimpse();
if ($peek['value'] == '.') {
return $this->StateFieldPathExpression();
}
if ($peek['value'] == '(') {
// do NOT directly go to FunctionsReturningString() because it doesnt check for custom functions.
return $this->FunctionDeclaration();
}
if ($peek['value'] == '.') {
return $this->StateFieldPathExpression();
} else if ($peek['value'] == '(') {
// do NOT directly go to FunctionsReturningString() because it doesnt check for custom functions.
return $this->FunctionDeclaration();
} else {
$this->syntaxError("'.' or '('"); $this->syntaxError("'.' or '('");
} break;
} else if ($this->_lexer->isNextToken(Lexer::T_STRING)) {
$this->match(Lexer::T_STRING);
return $this->_lexer->token['value']; case Lexer::T_STRING:
} else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { $this->match(Lexer::T_STRING);
return $this->InputParameter();
} else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { return $this->_lexer->token['value'];
return $this->AggregateExpression();
} else if (in_array($this->_lexer->lookahead['type'], array(Lexer::T_CASE, Lexer::T_COALESCE, Lexer::T_NULLIF))) { case Lexer::T_INPUT_PARAMETER:
return $this->CaseExpression(); return $this->InputParameter();
case Lexer::T_CASE:
case Lexer::T_COALESCE:
case Lexer::T_NULLIF:
return $this->CaseExpression();
default:
if ($this->_isAggregateFunction($lookaheadType)) {
return $this->AggregateExpression();
}
} }
$this->syntaxError('StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression'); $this->syntaxError(
'StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression'
);
} }
/** /**
@ -2564,40 +2617,28 @@ class Parser
*/ */
public function AggregateExpression() public function AggregateExpression()
{ {
$lookaheadType = $this->_lexer->lookahead['type'];
$isDistinct = false; $isDistinct = false;
$functionName = '';
if ($this->_lexer->isNextToken(Lexer::T_COUNT)) { if ( ! in_array($lookaheadType, array(Lexer::T_COUNT, Lexer::T_AVG, Lexer::T_MAX, Lexer::T_MIN, Lexer::T_SUM))) {
$this->match(Lexer::T_COUNT); $this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT');
$functionName = $this->_lexer->token['value'];
$this->match(Lexer::T_OPEN_PARENTHESIS);
if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
$this->match(Lexer::T_DISTINCT);
$isDistinct = true;
}
$pathExp = $this->SingleValuedPathExpression();
$this->match(Lexer::T_CLOSE_PARENTHESIS);
} else {
if ($this->_lexer->isNextToken(Lexer::T_AVG)) {
$this->match(Lexer::T_AVG);
} else if ($this->_lexer->isNextToken(Lexer::T_MAX)) {
$this->match(Lexer::T_MAX);
} else if ($this->_lexer->isNextToken(Lexer::T_MIN)) {
$this->match(Lexer::T_MIN);
} else if ($this->_lexer->isNextToken(Lexer::T_SUM)) {
$this->match(Lexer::T_SUM);
} else {
$this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT');
}
$functionName = $this->_lexer->token['value'];
$this->match(Lexer::T_OPEN_PARENTHESIS);
$pathExp = $this->SimpleArithmeticExpression();
$this->match(Lexer::T_CLOSE_PARENTHESIS);
} }
$this->match($lookaheadType);
$functionName = $this->_lexer->token['value'];
$this->match(Lexer::T_OPEN_PARENTHESIS);
if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
$this->match(Lexer::T_DISTINCT);
$isDistinct = true;
}
$pathExp = ($lookaheadType === Lexer::T_COUNT)
? $this->SingleValuedPathExpression()
: $this->SimpleArithmeticExpression();
$this->match(Lexer::T_CLOSE_PARENTHESIS);
return new AST\AggregateExpression($functionName, $pathExp, $isDistinct); return new AST\AggregateExpression($functionName, $pathExp, $isDistinct);
} }
@ -2608,24 +2649,19 @@ class Parser
*/ */
public function QuantifiedExpression() public function QuantifiedExpression()
{ {
$type = ''; $lookaheadType = $this->_lexer->lookahead['type'];
$value = $this->_lexer->lookahead['value'];
if ($this->_lexer->isNextToken(Lexer::T_ALL)) { if ( ! in_array($lookaheadType, array(Lexer::T_ALL, Lexer::T_ANY, Lexer::T_SOME))) {
$this->match(Lexer::T_ALL);
$type = 'ALL';
} else if ($this->_lexer->isNextToken(Lexer::T_ANY)) {
$this->match(Lexer::T_ANY);
$type = 'ANY';
} else if ($this->_lexer->isNextToken(Lexer::T_SOME)) {
$this->match(Lexer::T_SOME);
$type = 'SOME';
} else {
$this->syntaxError('ALL, ANY or SOME'); $this->syntaxError('ALL, ANY or SOME');
} }
$this->match($lookaheadType);
$this->match(Lexer::T_OPEN_PARENTHESIS); $this->match(Lexer::T_OPEN_PARENTHESIS);
$qExpr = new AST\QuantifiedExpression($this->Subselect()); $qExpr = new AST\QuantifiedExpression($this->Subselect());
$qExpr->type = $type; $qExpr->type = $value;
$this->match(Lexer::T_CLOSE_PARENTHESIS); $this->match(Lexer::T_CLOSE_PARENTHESIS);
return $qExpr; return $qExpr;
@ -2666,14 +2702,11 @@ class Parser
{ {
$peek = $this->_lexer->glimpse(); $peek = $this->_lexer->glimpse();
$leftExpr = $this->ArithmeticExpression(); $leftExpr = $this->ArithmeticExpression();
$operator = $this->ComparisonOperator(); $operator = $this->ComparisonOperator();
$rightExpr = ($this->_isNextAllAnySome())
if ($this->_isNextAllAnySome()) { ? $this->QuantifiedExpression()
$rightExpr = $this->QuantifiedExpression(); : $this->ArithmeticExpression();
} else {
$rightExpr = $this->ArithmeticExpression();
}
return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr); return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr);
} }