Improved code readability. Improved performance.
This commit is contained in:
parent
356f5874bf
commit
5b73f1bd82
@ -23,8 +23,9 @@ namespace Doctrine\ORM\Internal;
|
||||
* The CommitOrderCalculator is used by the UnitOfWork to sort out the
|
||||
* correct order in which changes to entities need to be persisted.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
*/
|
||||
class CommitOrderCalculator
|
||||
{
|
||||
@ -60,10 +61,9 @@ class CommitOrderCalculator
|
||||
{
|
||||
// Check whether we need to do anything. 0 or 1 node is easy.
|
||||
$nodeCount = count($this->_classes);
|
||||
if ($nodeCount == 0) {
|
||||
return array();
|
||||
} else if ($nodeCount == 1) {
|
||||
return array_values($this->_classes);
|
||||
|
||||
if ($nodeCount <= 1) {
|
||||
return ($nodeCount == 1) ? array_values($this->_classes) : array();
|
||||
}
|
||||
|
||||
// Init
|
||||
|
@ -36,11 +36,6 @@ use PDO,
|
||||
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
|
||||
*
|
||||
* @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
|
||||
{
|
||||
|
@ -164,7 +164,7 @@ final class PersistentCollection implements Collection
|
||||
|
||||
// If _backRefFieldName is set and its a one-to-many association,
|
||||
// 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
|
||||
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
|
||||
$element, $this->owner
|
||||
@ -189,7 +189,7 @@ final class PersistentCollection implements Collection
|
||||
|
||||
// If _backRefFieldName is set, then the association is bidirectional
|
||||
// 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
|
||||
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
|
||||
$element, $this->owner
|
||||
@ -304,7 +304,7 @@ final class PersistentCollection implements Collection
|
||||
|
||||
if ($this->association !== null &&
|
||||
$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->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
|
||||
}
|
||||
@ -425,7 +425,7 @@ final class PersistentCollection implements Collection
|
||||
$this->changed();
|
||||
|
||||
if ($this->association !== null &&
|
||||
$this->association['type'] == ClassMetadata::ONE_TO_MANY &&
|
||||
$this->association['type'] === ClassMetadata::ONE_TO_MANY &&
|
||||
$this->association['orphanRemoval']) {
|
||||
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
|
||||
}
|
||||
@ -448,7 +448,7 @@ final class PersistentCollection implements Collection
|
||||
*/
|
||||
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);
|
||||
|
||||
return $this->coll->contains($element) || $persister->contains($this, $element);
|
||||
@ -514,7 +514,7 @@ final class PersistentCollection implements Collection
|
||||
*/
|
||||
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);
|
||||
|
||||
return $persister->count($this) + ($this->isDirty ? $this->coll->count() : 0);
|
||||
@ -630,7 +630,7 @@ final class PersistentCollection implements Collection
|
||||
|
||||
$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,
|
||||
// hence for event listeners we need the objects in memory.
|
||||
$this->initialize();
|
||||
|
@ -49,7 +49,7 @@ class Lexer extends \Doctrine\Common\Lexer
|
||||
const T_PLUS = 17;
|
||||
const T_OPEN_CURLY_BRACE = 18;
|
||||
const T_CLOSE_CURLY_BRACE = 19;
|
||||
|
||||
|
||||
// All tokens that are also identifiers should be >= 100
|
||||
const T_IDENTIFIER = 100;
|
||||
const T_ALL = 101;
|
||||
@ -133,7 +133,7 @@ class Lexer extends \Doctrine\Common\Lexer
|
||||
'\?[0-9]*|:[a-z]{1}[a-z0-9_]{0,}'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@ -149,50 +149,58 @@ class Lexer extends \Doctrine\Common\Lexer
|
||||
{
|
||||
$type = self::T_NONE;
|
||||
|
||||
// Recognizing numeric values
|
||||
if (is_numeric($value)) {
|
||||
return (strpos($value, '.') !== false || stripos($value, 'e') !== false)
|
||||
? self::T_FLOAT : self::T_INTEGER;
|
||||
}
|
||||
|
||||
// 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;
|
||||
switch (true) {
|
||||
// Recognize numeric values
|
||||
case (is_numeric($value)):
|
||||
if (strpos($value, '.') !== false || stripos($value, 'e') !== false) {
|
||||
return self::T_FLOAT;
|
||||
}
|
||||
}
|
||||
|
||||
return self::T_IDENTIFIER;
|
||||
} else if ($value[0] === '?' || $value[0] === ':') {
|
||||
return self::T_INPUT_PARAMETER;
|
||||
} else {
|
||||
switch ($value) {
|
||||
case '.': return self::T_DOT;
|
||||
case ',': return self::T_COMMA;
|
||||
case '(': return self::T_OPEN_PARENTHESIS;
|
||||
case ')': return self::T_CLOSE_PARENTHESIS;
|
||||
case '=': return self::T_EQUALS;
|
||||
case '>': return self::T_GREATER_THAN;
|
||||
case '<': return self::T_LOWER_THAN;
|
||||
case '+': return self::T_PLUS;
|
||||
case '-': return self::T_MINUS;
|
||||
case '*': return self::T_MULTIPLY;
|
||||
case '/': return self::T_DIVIDE;
|
||||
case '!': return self::T_NEGATE;
|
||||
case '{': return self::T_OPEN_CURLY_BRACE;
|
||||
case '}': return self::T_CLOSE_CURLY_BRACE;
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
return self::T_INTEGER;
|
||||
|
||||
// Recognize quoted strings
|
||||
case ($value[0] === "'"):
|
||||
$value = str_replace("''", "'", substr($value, 1, strlen($value) - 2));
|
||||
|
||||
return self::T_STRING;
|
||||
|
||||
// Recognize identifiers
|
||||
case (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;
|
||||
|
||||
// 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;
|
||||
|
@ -677,13 +677,10 @@ class Parser
|
||||
}
|
||||
|
||||
// Build the error message
|
||||
$semanticalError = 'Invalid PathExpression. ';
|
||||
|
||||
if (count($expectedStringTypes) == 1) {
|
||||
$semanticalError .= 'Must be a ' . $expectedStringTypes[0] . '.';
|
||||
} else {
|
||||
$semanticalError .= implode(' or ', $expectedStringTypes) . ' expected.';
|
||||
}
|
||||
$semanticalError = 'Invalid PathExpression. ';
|
||||
$semanticalError .= (count($expectedStringTypes) == 1)
|
||||
? 'Must be a ' . $expectedStringTypes[0] . '.'
|
||||
: implode(' or ', $expectedStringTypes) . ' expected.';
|
||||
|
||||
$this->semanticalError($semanticalError, $deferredItem['token']);
|
||||
}
|
||||
@ -1866,53 +1863,78 @@ class Parser
|
||||
$expression = null;
|
||||
$identVariable = null;
|
||||
$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)
|
||||
$expression = $this->ScalarExpression();
|
||||
} 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)
|
||||
case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] === Lexer::T_DOT):
|
||||
$expression = $this->ScalarExpression();
|
||||
} else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
|
||||
// COUNT(u.id)
|
||||
$expression = $this->AggregateExpression();
|
||||
} else {
|
||||
// SUM(u.id)
|
||||
$expression = $this->FunctionDeclaration();
|
||||
}
|
||||
} else if ($this->_lexer->lookahead['type'] === Lexer::T_PARTIAL) {
|
||||
break;
|
||||
|
||||
// IdentificationVariable (u)
|
||||
case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] !== Lexer::T_OPEN_PARENTHESIS):
|
||||
$expression = $identVariable = $this->IdentificationVariable();
|
||||
break;
|
||||
|
||||
// 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})
|
||||
$expression = $this->PartialObjectExpression();
|
||||
$identVariable = $expression->identificationVariable;
|
||||
} else if ($this->_lexer->lookahead['type'] === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT) {
|
||||
case ($lookaheadType === Lexer::T_PARTIAL):
|
||||
$expression = $this->PartialObjectExpression();
|
||||
$identVariable = $expression->identificationVariable;
|
||||
break;
|
||||
|
||||
// Subselect
|
||||
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$expression = $this->Subselect();
|
||||
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
} else if (in_array($this->_lexer->lookahead['type'], array(Lexer::T_OPEN_PARENTHESIS, Lexer::T_INTEGER, Lexer::T_FLOAT, Lexer::T_STRING))) {
|
||||
case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT):
|
||||
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$expression = $this->Subselect();
|
||||
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
break;
|
||||
|
||||
// Shortcut: ScalarExpression => SimpleArithmeticExpression
|
||||
$expression = $this->SimpleArithmeticExpression();
|
||||
} else if (in_array($this->_lexer->lookahead['type'], array(Lexer::T_PLUS, Lexer::T_MINUS))) {
|
||||
// SimpleArithmeticExpression : (- u.value ) or ( + u.value )
|
||||
$expression = $this->SimpleArithmeticExpression();
|
||||
} else {
|
||||
$this->syntaxError(
|
||||
'IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression',
|
||||
$this->_lexer->lookahead
|
||||
);
|
||||
case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS):
|
||||
case ($lookaheadType === Lexer::T_INTEGER):
|
||||
case ($lookaheadType === Lexer::T_STRING):
|
||||
case ($lookaheadType === Lexer::T_FLOAT):
|
||||
// SimpleArithmeticExpression : (- u.value ) or ( + u.value )
|
||||
case ($lookaheadType === Lexer::T_MINUS):
|
||||
case ($lookaheadType === Lexer::T_PLUS):
|
||||
$expression = $this->SimpleArithmeticExpression();
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->syntaxError(
|
||||
'IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression',
|
||||
$this->_lexer->lookahead
|
||||
);
|
||||
}
|
||||
|
||||
// [["AS"] ["HIDDEN"] AliasResultVariable]
|
||||
@ -1965,25 +1987,41 @@ class Parser
|
||||
{
|
||||
$peek = $this->_lexer->glimpse();
|
||||
|
||||
if ($peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) {
|
||||
// SingleValuedPathExpression | IdentificationVariable
|
||||
$expression = ($peek['value'] == '.')
|
||||
? $this->StateFieldPathExpression()
|
||||
: $this->IdentificationVariable();
|
||||
switch ($this->_lexer->lookahead['type']) {
|
||||
case Lexer::T_IDENTIFIER:
|
||||
switch (true) {
|
||||
case ($peek['type'] === Lexer::T_DOT):
|
||||
$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
|
||||
$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($expression);
|
||||
return new AST\SimpleSelectExpression($expression);
|
||||
|
||||
default:
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
$this->_lexer->peek();
|
||||
@ -2099,27 +2137,26 @@ class Parser
|
||||
{
|
||||
$condPrimary = new AST\ConditionalPrimary;
|
||||
|
||||
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 {
|
||||
if ( ! $this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
|
||||
$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;
|
||||
}
|
||||
|
||||
@ -2132,10 +2169,10 @@ class Parser
|
||||
*/
|
||||
public function SimpleConditionalExpression()
|
||||
{
|
||||
$token = $this->_lexer->lookahead;
|
||||
|
||||
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
|
||||
$token = $this->_lexer->glimpse();
|
||||
} else {
|
||||
$token = $this->_lexer->lookahead;
|
||||
}
|
||||
|
||||
if ($token['type'] === Lexer::T_EXISTS) {
|
||||
@ -2464,9 +2501,9 @@ class Parser
|
||||
}
|
||||
|
||||
return $this->FunctionDeclaration();
|
||||
} else {
|
||||
return $this->Literal();
|
||||
}
|
||||
|
||||
return $this->Literal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2498,30 +2535,46 @@ class Parser
|
||||
*/
|
||||
public function StringPrimary()
|
||||
{
|
||||
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$peek = $this->_lexer->glimpse();
|
||||
$lookaheadType = $this->_lexer->lookahead['type'];
|
||||
|
||||
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 '('");
|
||||
}
|
||||
} else if ($this->_lexer->isNextToken(Lexer::T_STRING)) {
|
||||
$this->match(Lexer::T_STRING);
|
||||
break;
|
||||
|
||||
return $this->_lexer->token['value'];
|
||||
} else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
|
||||
return $this->InputParameter();
|
||||
} else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
|
||||
return $this->AggregateExpression();
|
||||
} else if (in_array($this->_lexer->lookahead['type'], array(Lexer::T_CASE, Lexer::T_COALESCE, Lexer::T_NULLIF))) {
|
||||
return $this->CaseExpression();
|
||||
case Lexer::T_STRING:
|
||||
$this->match(Lexer::T_STRING);
|
||||
|
||||
return $this->_lexer->token['value'];
|
||||
|
||||
case Lexer::T_INPUT_PARAMETER:
|
||||
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()
|
||||
{
|
||||
$lookaheadType = $this->_lexer->lookahead['type'];
|
||||
$isDistinct = false;
|
||||
$functionName = '';
|
||||
|
||||
if ($this->_lexer->isNextToken(Lexer::T_COUNT)) {
|
||||
$this->match(Lexer::T_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);
|
||||
if ( ! in_array($lookaheadType, array(Lexer::T_COUNT, Lexer::T_AVG, Lexer::T_MAX, Lexer::T_MIN, Lexer::T_SUM))) {
|
||||
$this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT');
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
@ -2608,24 +2649,19 @@ class Parser
|
||||
*/
|
||||
public function QuantifiedExpression()
|
||||
{
|
||||
$type = '';
|
||||
$lookaheadType = $this->_lexer->lookahead['type'];
|
||||
$value = $this->_lexer->lookahead['value'];
|
||||
|
||||
if ($this->_lexer->isNextToken(Lexer::T_ALL)) {
|
||||
$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 {
|
||||
if ( ! in_array($lookaheadType, array(Lexer::T_ALL, Lexer::T_ANY, Lexer::T_SOME))) {
|
||||
$this->syntaxError('ALL, ANY or SOME');
|
||||
}
|
||||
|
||||
$this->match($lookaheadType);
|
||||
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$qExpr = new AST\QuantifiedExpression($this->Subselect());
|
||||
$qExpr->type = $type;
|
||||
$qExpr->type = $value;
|
||||
|
||||
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
|
||||
return $qExpr;
|
||||
@ -2666,14 +2702,11 @@ class Parser
|
||||
{
|
||||
$peek = $this->_lexer->glimpse();
|
||||
|
||||
$leftExpr = $this->ArithmeticExpression();
|
||||
$operator = $this->ComparisonOperator();
|
||||
|
||||
if ($this->_isNextAllAnySome()) {
|
||||
$rightExpr = $this->QuantifiedExpression();
|
||||
} else {
|
||||
$rightExpr = $this->ArithmeticExpression();
|
||||
}
|
||||
$leftExpr = $this->ArithmeticExpression();
|
||||
$operator = $this->ComparisonOperator();
|
||||
$rightExpr = ($this->_isNextAllAnySome())
|
||||
? $this->QuantifiedExpression()
|
||||
: $this->ArithmeticExpression();
|
||||
|
||||
return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user