From 3f60b8b5b598f954bfb3e0a151d8ff6f7341dddd Mon Sep 17 00:00:00 2001 From: romanb Date: Tue, 20 Jan 2009 17:07:07 +0000 Subject: [PATCH] More DQL parser work. First basic WHERE conditions. Changed scanner according to new positional parameter syntax (?) --- .../ORM/Query/AST/ArithmeticExpression.php | 49 ++++ .../ORM/Query/AST/ArithmeticFactor.php | 40 +++ lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php | 26 ++ .../ORM/Query/AST/ComparisonExpression.php | 33 ++- .../ORM/Query/AST/ComparisonOperator.php | 37 +++ .../ORM/Query/AST/ConditionalExpression.php | 2 +- .../ORM/Query/AST/ConditionalPrimary.php | 10 + lib/Doctrine/ORM/Query/AST/InputParameter.php | 49 ++++ lib/Doctrine/ORM/Query/AST/PathExpression.php | 11 + .../Query/AST/SimpleArithmeticExpression.php | 26 ++ .../Query/AST/SimpleConditionalExpression.php | 16 -- lib/Doctrine/ORM/Query/Parser.php | 271 ++++++++++++++---- lib/Doctrine/ORM/Query/Scanner.php | 2 +- lib/Doctrine/ORM/Query/SqlWalker.php | 118 ++++++++ lib/Doctrine/ORM/Query/Token.php | 98 +++---- tests/Orm/Query/SelectSqlGenerationTest.php | 3 +- 16 files changed, 674 insertions(+), 117 deletions(-) create mode 100644 lib/Doctrine/ORM/Query/AST/ArithmeticExpression.php create mode 100644 lib/Doctrine/ORM/Query/AST/ArithmeticFactor.php create mode 100644 lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php create mode 100644 lib/Doctrine/ORM/Query/AST/ComparisonOperator.php create mode 100644 lib/Doctrine/ORM/Query/AST/InputParameter.php create mode 100644 lib/Doctrine/ORM/Query/AST/SimpleArithmeticExpression.php delete mode 100644 lib/Doctrine/ORM/Query/AST/SimpleConditionalExpression.php diff --git a/lib/Doctrine/ORM/Query/AST/ArithmeticExpression.php b/lib/Doctrine/ORM/Query/AST/ArithmeticExpression.php new file mode 100644 index 000000000..a39157548 --- /dev/null +++ b/lib/Doctrine/ORM/Query/AST/ArithmeticExpression.php @@ -0,0 +1,49 @@ +_subselect) throw new Doctrine_Exception; + $this->_simpleArithmeticExpression = $simpleArithmeticExpr; + } + + public function setSubselect($subselect) + { + if ($this->_simpleArithmeticExpression) throw new Doctrine_Exception; + $this->_subselect = $subselect; + } + + public function getSimpleArithmeticExpression() + { + return $this->_simpleArithmeticExpression; + } + + public function getSubselect() + { + return $this->_subselect; + } + + public function isSimpleArithmeticExpression() + { + return (bool)$this->_simpleArithmeticExpression; + } + + public function isSubselect() + { + return (bool)$this->_subselect; + } +} + diff --git a/lib/Doctrine/ORM/Query/AST/ArithmeticFactor.php b/lib/Doctrine/ORM/Query/AST/ArithmeticFactor.php new file mode 100644 index 000000000..343e95893 --- /dev/null +++ b/lib/Doctrine/ORM/Query/AST/ArithmeticFactor.php @@ -0,0 +1,40 @@ +_arithmeticPrimary = $arithmeticPrimary; + $this->_pSigned = $pSigned; + $this->_nSigned = $nSigned; + } + + public function getArithmeticPrimary() + { + return $this->_arithmeticPrimary; + } + + public function isPositiveSigned() + { + return $this->_pSigned; + } + + public function isNegativeSigned() + { + return $this->_nSigned; + } +} + diff --git a/lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php b/lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php new file mode 100644 index 000000000..5dad83b45 --- /dev/null +++ b/lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php @@ -0,0 +1,26 @@ +_factors = $arithmeticFactors; + } + + public function getArithmeticFactors() + { + return $this->_factors; + } +} + diff --git a/lib/Doctrine/ORM/Query/AST/ComparisonExpression.php b/lib/Doctrine/ORM/Query/AST/ComparisonExpression.php index c46d736f8..f8943831b 100644 --- a/lib/Doctrine/ORM/Query/AST/ComparisonExpression.php +++ b/lib/Doctrine/ORM/Query/AST/ComparisonExpression.php @@ -5,12 +5,41 @@ */ /** - * Description of ComparisonExpression + * ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression ) | + * StringExpression ComparisonOperator (StringExpression | QuantifiedExpression) | + * BooleanExpression ("=" | "<>" | "!=") (BooleanExpression | QuantifiedExpression) | + * EnumExpression ("=" | "<>" | "!=") (EnumExpression | QuantifiedExpression) | + * DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) | + * EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression) * * @author robo */ class Doctrine_ORM_Query_AST_ComparisonExpression extends Doctrine_ORM_Query_AST { - + private $_leftExpr; + private $_rightExpr; + private $_operator; + + public function __construct($leftExpr, $operator, $rightExpr) + { + $this->_leftExpr = $leftExpr; + $this->_rightExpr = $rightExpr; + $this->_operator = $operator; + } + + public function getLeftExpression() + { + return $this->_leftExpr; + } + + public function getRightExpression() + { + return $this->_rightExpr; + } + + public function getOperator() + { + return $this->_operator; + } } diff --git a/lib/Doctrine/ORM/Query/AST/ComparisonOperator.php b/lib/Doctrine/ORM/Query/AST/ComparisonOperator.php new file mode 100644 index 000000000..87d256a3e --- /dev/null +++ b/lib/Doctrine/ORM/Query/AST/ComparisonOperator.php @@ -0,0 +1,37 @@ +. + */ + +/** + * ComparisonOperator = "=" | "<" | "<=" | "<>" | ">" | ">=" | "!=" + * + * @package Doctrine + * @subpackage Query + * @author Guilherme Blanco + * @author Janne Vanhala + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + * @version $Revision$ + */ +class Doctrine_ORM_Query_AST_ComparisonOperator extends Doctrine_ORM_Query_AST +{ + +} diff --git a/lib/Doctrine/ORM/Query/AST/ConditionalExpression.php b/lib/Doctrine/ORM/Query/AST/ConditionalExpression.php index 2434c8ae3..34f620aee 100644 --- a/lib/Doctrine/ORM/Query/AST/ConditionalExpression.php +++ b/lib/Doctrine/ORM/Query/AST/ConditionalExpression.php @@ -20,7 +20,7 @@ class Doctrine_ORM_Query_AST_ConditionalExpression extends Doctrine_ORM_Query_AS public function getConditionalTerms() { - return $this->_conditionalTerm; + return $this->_conditionalTerms; } } diff --git a/lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php b/lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php index 9ff301d6e..61e9e45c2 100644 --- a/lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php +++ b/lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php @@ -33,5 +33,15 @@ class Doctrine_ORM_Query_AST_ConditionalPrimary extends Doctrine_ORM_Query_AST { return $this->_conditionalExpression; } + + public function isSimpleConditionalExpression() + { + return (bool)$this->_simpleConditionalExpression; + } + + public function isConditionalExpression() + { + return (bool)$this->_conditionalExpression; + } } diff --git a/lib/Doctrine/ORM/Query/AST/InputParameter.php b/lib/Doctrine/ORM/Query/AST/InputParameter.php new file mode 100644 index 000000000..0e47dfce1 --- /dev/null +++ b/lib/Doctrine/ORM/Query/AST/InputParameter.php @@ -0,0 +1,49 @@ +_isNamed = ! is_numeric($param); + if ($this->_isNamed) { + $this->_name = $param; + } else { + $this->_position = $param; + } + } + + public function isNamed() + { + return $this->_isNamed; + } + + public function isPositional() + { + return ! $this->_isNamed; + } + + public function getName() + { + return $this->_name; + } + + public function getPosition() + { + return $this->_position; + } +} + diff --git a/lib/Doctrine/ORM/Query/AST/PathExpression.php b/lib/Doctrine/ORM/Query/AST/PathExpression.php index 20683ca8a..a352e8fad 100644 --- a/lib/Doctrine/ORM/Query/AST/PathExpression.php +++ b/lib/Doctrine/ORM/Query/AST/PathExpression.php @@ -17,6 +17,7 @@ class Doctrine_ORM_Query_AST_PathExpression private $_isSimpleStateFieldAssociationPathExpression = false; private $_embeddedClassFields = array(); private $_singleValuedAssociationFields = array(); + private $_collectionValuedAssociationFields = array(); public function __construct(array $parts) { @@ -61,6 +62,11 @@ class Doctrine_ORM_Query_AST_PathExpression return isset($this->_singleValuedAssociationFields[$part]); } + public function isPartCollectionValuedAssociationField($part) + { + return isset($this->_collectionValuedAssociationFields[$part]); + } + /* Setters to attach semantical information during semantical analysis. */ public function setIsSimpleStateFieldPathExpression($bool) @@ -82,5 +88,10 @@ class Doctrine_ORM_Query_AST_PathExpression { $this->_singleValuedAssociationFields[$part] = true; } + + public function setIsCollectionValuedAssociationPart($part) + { + $this->_collectionValuedAssociationFields[$part] = true; + } } diff --git a/lib/Doctrine/ORM/Query/AST/SimpleArithmeticExpression.php b/lib/Doctrine/ORM/Query/AST/SimpleArithmeticExpression.php new file mode 100644 index 000000000..e87d2acab --- /dev/null +++ b/lib/Doctrine/ORM/Query/AST/SimpleArithmeticExpression.php @@ -0,0 +1,26 @@ +_terms = $arithmeticTerms; + } + + public function getArithmeticTerms() + { + return $this->_terms; + } +} + diff --git a/lib/Doctrine/ORM/Query/AST/SimpleConditionalExpression.php b/lib/Doctrine/ORM/Query/AST/SimpleConditionalExpression.php deleted file mode 100644 index c3b3ef199..000000000 --- a/lib/Doctrine/ORM/Query/AST/SimpleConditionalExpression.php +++ /dev/null @@ -1,16 +0,0 @@ -_IdentificationVariable(); + if ( ! $this->_parserResult->hasQueryComponent($identificationVariable)) { + $this->syntaxError("Identification variable."); + } + $qComp = $this->_parserResult->getQueryComponent($identificationVariable); + $parts[] = $identificationVariable; + + $class = $qComp['metadata']; + + if ( ! $this->_isNextToken('.')) { + $this->syntaxError(); + } + + while ($this->_isNextToken('.')) { + if ($stateFieldSeen) $this->syntaxError(); + $this->match('.'); + $part = $this->_IdentificationVariable(); + if ($class->hasField($part)) { + $stateFieldSeen = true; + } else if ($class->hasAssociation($part)) { + $assoc = $class->getAssociationMapping($part); + $class = $this->_em->getClassMetadata($assoc->getTargetEntityName()); + $assocSeen = true; + } else { + $this->syntaxError(); + } + $parts[] = $part; + } + + $pathExpr = new Doctrine_ORM_Query_AST_PathExpression($parts); + + if ($assocSeen) { + $pathExpr->setIsSimpleStateFieldAssociationPathExpression(true); + } else { + $pathExpr->setIsSimpleStateFieldPathExpression(true); + } + + return $pathExpr; + } + /** * AggregateExpression ::= * ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" | @@ -963,52 +1012,6 @@ class Doctrine_ORM_Query_Parser * EmptyCollectionComparisonExpression | CollectionMemberExpression */ private function _SimpleConditionalExpression() - { - if ($this->_getExpressionType() === Doctrine_ORM_Query_Token::T_EXISTS) { - return $this->_ExistsExpression(); - } - - // For now... just SimpleStateFieldPathExpression - $leftExpression = $this->_SimpleStateFieldPathExpression(); - - switch ($this->_getExpressionType()) { - case Doctrine_ORM_Query_Token::T_NONE: - // [TODO] Check out ticket #935 to understand what will be done with enumParams - $rightExpression = $this->_ComparisonExpression(); - break; - case Doctrine_ORM_Query_Token::T_BETWEEN: - $rightExpression = $this->_BetweenExpression(); - break; - - case Doctrine_ORM_Query_Token::T_LIKE: - $rightExpression = $this->_LikeExpression(); - break; - - case Doctrine_ORM_Query_Token::T_IN: - $rightExpression = $this->_InExpression(); - break; - - case Doctrine_ORM_Query_Token::T_IS: - $rightExpression = $this->_NullComparisonExpression(); - break; - - case Doctrine_ORM_Query_Token::T_ALL: - case Doctrine_ORM_Query_Token::T_ANY: - case Doctrine_ORM_Query_Token::T_SOME: - $rightExpression = $this->_QuantifiedExpression(); - break; - - default: - $message = "BETWEEN, LIKE, IN, IS, quantified (ALL, ANY or SOME) " - . "or comparison (=, <, <=, <>, >, >=, !=)"; - $this->syntaxError($message); - break; - } - - - } - - private function _getExpressionType() { if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_NOT)) { $token = $this->_scanner->peek(); @@ -1016,11 +1019,183 @@ class Doctrine_ORM_Query_Parser } else { $token = $this->lookahead; } - return $token['type']; + if ($token['type'] === Doctrine_ORM_Query_Token::T_EXISTS) { + return $this->_ExistsExpression(); + } + + $stateFieldPathExpr = false; + if ($token['type'] === Doctrine_ORM_Query_Token::T_IDENTIFIER) { + // Peek beyond the PathExpression + $stateFieldPathExpr = true; + $peek = $this->_scanner->peek(); + while ($peek['value'] === '.') { + $this->_scanner->peek(); + $peek = $this->_scanner->peek(); + } + $this->_scanner->resetPeek(); + $token = $peek; + } + + if ($stateFieldPathExpr) { + switch ($token['type']) { + case Doctrine_ORM_Query_Token::T_BETWEEN: + return $this->_BetweenExpression(); + case Doctrine_ORM_Query_Token::T_LIKE: + return $this->_LikeExpression(); + case Doctrine_ORM_Query_Token::T_IN: + return $this->_InExpression(); + case Doctrine_ORM_Query_Token::T_IS: + return $this->_NullComparisonExpression(); + case Doctrine_ORM_Query_Token::T_NONE: + return $this->_ComparisonExpression(); + default: + $this->syntaxError(); + } + } else { + switch ($token['type']) { + case Doctrine_ORM_Query_Token::T_INTEGER: + // IF it turns out its a ComparisonExpression, then it MUST be ArithmeticExpression + break; + case Doctrine_ORM_Query_Token::T_STRING: + // IF it turns out its a ComparisonExpression, then it MUST be StringExpression + break; + default: + $this->syntaxError(); + } + } } + /** + * SIMPLIFIED FROM BNF FOR NOW + * ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression ) + */ private function _ComparisonExpression() { - var_dump($this->lookahead); + $leftExpr = $this->_ArithmeticExpression(); + $operator = $this->_ComparisonOperator(); + if ($this->lookahead['type'] === Doctrine_ORM_Query_Token::T_ALL || + $this->lookahead['type'] === Doctrine_ORM_Query_Token::T_ANY || + $this->lookahead['type'] === Doctrine_ORM_Query_Token::T_SOME) { + $rightExpr = $this->_QuantifiedExpression(); + } else { + $rightExpr = $this->_ArithmeticExpression(); + } + return new Doctrine_ORM_Query_AST_ComparisonExpression($leftExpr, $operator, $rightExpr); + } + + /** + * ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")" + */ + private function _ArithmeticExpression() + { + $expr = new Doctrine_ORM_Query_AST_ArithmeticExpression; + if ($this->lookahead['value'] === '(') { + $peek = $this->_scanner->peek(); + $this->_scanner->resetPeek(); + if ($peek['type'] === Doctrine_ORM_Query_Token::T_SELECT) { + $expr->setSubselect($this->_Subselect()); + return $expr; + } + } + $expr->setSimpleArithmeticExpression($this->_SimpleArithmeticExpression()); + return $expr; + } + + /** + * SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}* + */ + private function _SimpleArithmeticExpression() + { + $terms = array(); + $terms[] = $this->_ArithmeticTerm(); + while ($this->lookahead['value'] == '+' || $this->lookahead['value'] == '-') { + $terms[] = $this->_ArithmeticTerm(); + } + return new Doctrine_ORM_Query_AST_SimpleArithmeticExpression($terms); + } + + /** + * ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}* + */ + private function _ArithmeticTerm() + { + $factors = array(); + $factors[] = $this->_ArithmeticFactor(); + while ($this->lookahead['value'] == '*' || $this->lookahead['value'] == '/') { + $factors[] = $this->_ArithmeticFactor(); + } + return new Doctrine_ORM_Query_AST_ArithmeticTerm($factors); + } + + /** + * ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary + */ + private function _ArithmeticFactor() + { + $pSign = $nSign = false; + if ($this->lookahead['value'] == '+') { + $this->match('+'); + $pSign = true; + } else if ($this->lookahead['value'] == '-') { + $this->match('-'); + $nSign = true; + } + return new Doctrine_ORM_Query_AST_ArithmeticFactor($this->_ArithmeticPrimary(), $pSign, $nSign); + } + + /** + * ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression + */ + private function _ArithmeticPrimary() + { + if ($this->lookahead['type'] === Doctrine_ORM_Query_Token::T_IDENTIFIER) { + return $this->_StateFieldPathExpression(); + } + if ($this->lookahead['value'] === '(') { + return $this->_SimpleArithmeticExpression(); + } + if ($this->lookahead['type'] === Doctrine_ORM_Query_Token::T_INPUT_PARAMETER) { + $this->match($this->lookahead['value']); + return new Doctrine_ORM_Query_AST_InputParameter($this->token['value']); + } + //TODO... + } + + /** + * ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!=" + */ + private function _ComparisonOperator() + { + switch ($this->lookahead['value']) { + case '=': + $this->match('='); + return '='; + case '<': + $this->match('<'); + $operator = '<'; + if ($this->_isNextToken('=')) { + $this->match('='); + $operator .= '='; + } else if ($this->_isNextToken('>')) { + $this->match('>'); + $operator .= '>'; + } + return $operator; + case '>': + $this->match('>'); + $operator = '>'; + if ($this->_isNextToken('=')) { + $this->match('='); + $operator .= '='; + } + return $operator; + case '!': + $this->match('!'); + $this->match('='); + return '<>'; + default: + $this->_parser->syntaxError('=, <, <=, <>, >, >=, !='); + break; + } } } diff --git a/lib/Doctrine/ORM/Query/Scanner.php b/lib/Doctrine/ORM/Query/Scanner.php index 08acf9ccb..a0316473e 100644 --- a/lib/Doctrine/ORM/Query/Scanner.php +++ b/lib/Doctrine/ORM/Query/Scanner.php @@ -91,7 +91,7 @@ class Doctrine_ORM_Query_Scanner '[a-z_][a-z0-9_]*', '(?:[0-9]+(?:[,\.][0-9]+)*)(?:e[+-]?[0-9]+)?', "'(?:[^']|'')*'", - '\?|:[a-z]+' + '\?[0-9]+|:[a-z]+' ); $regex = '/(' . implode(')|(', $patterns) . ')|\s+|(.)/i'; } diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index a210229f5..d1c0eaa22 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -44,7 +44,9 @@ class Doctrine_ORM_Query_SqlWalker { $sql = $this->walkSelectClause($AST->getSelectClause()); $sql .= $this->walkFromClause($AST->getFromClause()); + $sql .= $AST->getWhereClause() ? $this->walkWhereClause($AST->getWhereClause()) : ''; $sql .= $AST->getGroupByClause() ? $this->walkGroupByClause($AST->getGroupByClause()) : ''; + //... more clauses return $sql; } @@ -223,6 +225,122 @@ class Doctrine_ORM_Query_SqlWalker } + public function walkWhereClause($whereClause) + { + $sql = ' WHERE '; + $condExpr = $whereClause->getConditionalExpression(); + foreach ($condExpr->getConditionalTerms() as $term) { + $sql .= $this->walkConditionalTerm($term); + } + return $sql; + } + + public function walkConditionalTerm($condTerm) + { + $sql = ''; + foreach ($condTerm->getConditionalFactors() as $factor) { + $sql .= $this->walkConditionalFactor($factor); + } + return $sql; + } + + public function walkConditionalFactor($factor) + { + $sql = ''; + if ($factor->isNot()) $sql .= ' NOT '; + $primary = $factor->getConditionalPrimary(); + if ($primary->isSimpleConditionalExpression()) { + $simpleCond = $primary->getSimpleConditionalExpression(); + if ($simpleCond instanceof Doctrine_ORM_Query_AST_ComparisonExpression) { + $sql .= $this->walkComparisonExpression($simpleCond); + } + // else if ... + } + + return $sql; + } + + public function walkComparisonExpression($compExpr) + { + $sql = ''; + if ($compExpr->getLeftExpression() instanceof Doctrine_ORM_Query_AST_ArithmeticExpression) { + $sql .= $this->walkArithmeticExpression($compExpr->getLeftExpression()); + } // else... + $sql .= ' ' . $compExpr->getOperator() . ' '; + if ($compExpr->getRightExpression() instanceof Doctrine_ORM_Query_AST_ArithmeticExpression) { + $sql .= $this->walkArithmeticExpression($compExpr->getRightExpression()); + } + return $sql; + } + + public function walkArithmeticExpression($arithmeticExpr) + { + $sql = ''; + if ($arithmeticExpr->isSimpleArithmeticExpression()) { + foreach ($arithmeticExpr->getSimpleArithmeticExpression()->getArithmeticTerms() as $term) { + $sql .= $this->walkArithmeticTerm($term); + } + } else { + $sql .= $this->walkSubselect($arithmeticExpr->getSubselect()); + } + return $sql; + } + + public function walkArithmeticTerm($term) + { + $sql = ''; + foreach ($term->getArithmeticFactors() as $factor) { + $sql .= $this->walkArithmeticFactor($factor); + } + return $sql; + } + + public function walkArithmeticFactor($factor) + { + $sql = ''; + $primary = $factor->getArithmeticPrimary(); + if ($primary instanceof Doctrine_ORM_Query_AST_PathExpression) { + $sql .= $this->walkPathExpression($primary); + } else if ($primary instanceof Doctrine_ORM_Query_AST_InputParameter) { + if ($primary->isNamed()) { + $sql .= ':' . $primary->getName(); + } else { + $sql .= '?'; + } + } + + // else... + + return $sql; + } + + public function walkPathExpression($pathExpr) + { + $sql = ''; + if ($pathExpr->isSimpleStateFieldPathExpression()) { + $parts = $pathExpr->getParts(); + $numParts = count($parts); + $dqlAlias = $parts[0]; + $fieldName = $parts[$numParts-1]; + $qComp = $this->_parserResult->getQueryComponent($dqlAlias); + $class = $qComp['metadata']; + + if ($numParts > 2) { + for ($i = 1; $i < $numParts-1; ++$i) { + //TODO + } + } + + $sqlTableAlias = $this->_dqlToSqlAliasMap[$dqlAlias]; + $sql .= $sqlTableAlias . '.' . $class->getColumnName($fieldName); + } else if ($pathExpr->isSimpleStateFieldAssociationPathExpression()) { + throw new Doctrine_Exception("Not yet implemented."); + } else { + throw new Doctrine_ORM_Query_Exception("Encountered invalid PathExpression during SQL construction."); + } + return $sql; + } + /** * Generates an SQL table alias from given table name and associates * it with given component alias diff --git a/lib/Doctrine/ORM/Query/Token.php b/lib/Doctrine/ORM/Query/Token.php index 333a0560b..53facfbc1 100644 --- a/lib/Doctrine/ORM/Query/Token.php +++ b/lib/Doctrine/ORM/Query/Token.php @@ -88,58 +88,11 @@ final class Doctrine_ORM_Query_Token const T_FALSE = 147; - protected $_keywordsTable = array(); + protected $_keywordsTable; public function __construct() { - $this->addKeyword(self::T_ALL, "ALL"); - $this->addKeyword(self::T_AND, "AND"); - $this->addKeyword(self::T_ANY, "ANY"); - $this->addKeyword(self::T_AS, "AS"); - $this->addKeyword(self::T_ASC, "ASC"); - $this->addKeyword(self::T_AVG, "AVG"); - $this->addKeyword(self::T_BETWEEN, "BETWEEN"); - $this->addKeyword(self::T_BY, "BY"); - $this->addKeyword(self::T_COMMA, ","); - $this->addKeyword(self::T_COUNT, "COUNT"); - $this->addKeyword(self::T_DELETE, "DELETE"); - $this->addKeyword(self::T_DESC, "DESC"); - $this->addKeyword(self::T_DISTINCT, "DISTINCT"); - $this->addKeyword(self::T_DOT, "."); - $this->addKeyword(self::T_ESCAPE, "ESPACE"); - $this->addKeyword(self::T_EXISTS, "EXISTS"); - $this->addKeyword(self::T_FALSE, "FALSE"); - $this->addKeyword(self::T_FROM, "FROM"); - $this->addKeyword(self::T_GROUP, "GROUP"); - $this->addKeyword(self::T_HAVING, "HAVING"); - $this->addKeyword(self::T_IN, "IN"); - $this->addKeyword(self::T_INDEX, "INDEX"); - $this->addKeyword(self::T_INNER, "INNER"); - $this->addKeyword(self::T_IS, "IS"); - $this->addKeyword(self::T_JOIN, "JOIN"); - $this->addKeyword(self::T_LEFT, "LEFT"); - $this->addKeyword(self::T_LIKE, "LIKE"); - $this->addKeyword(self::T_LIMIT, "LIMIT"); - $this->addKeyword(self::T_MAX, "MAX"); - $this->addKeyword(self::T_MIN, "MIN"); - $this->addKeyword(self::T_MOD, "MOD"); - $this->addKeyword(self::T_NOT, "NOT"); - $this->addKeyword(self::T_NULL, "NULL"); - $this->addKeyword(self::T_OFFSET, "OFFSET"); - $this->addKeyword(self::T_ON, "ON"); - $this->addKeyword(self::T_OR, "OR"); - $this->addKeyword(self::T_ORDER, "ORDER"); - $this->addKeyword(self::T_OUTER, "OUTER"); - $this->addKeyword(self::T_SELECT, "SELECT"); - $this->addKeyword(self::T_SET, "SET"); - $this->addKeyword(self::T_SIZE, "SIZE"); - $this->addKeyword(self::T_SOME, "SOME"); - $this->addKeyword(self::T_SUM, "SUM"); - $this->addKeyword(self::T_TRUE, "TRUE"); - $this->addKeyword(self::T_UPDATE, "UPDATE"); - $this->addKeyword(self::T_WHERE, "WHERE"); - $this->addKeyword(self::T_WITH, "WITH"); } @@ -151,6 +104,55 @@ final class Doctrine_ORM_Query_Token public function getLiteral($token) { + if ( ! $this->_keywordsTable) { + $this->addKeyword(self::T_ALL, "ALL"); + $this->addKeyword(self::T_AND, "AND"); + $this->addKeyword(self::T_ANY, "ANY"); + $this->addKeyword(self::T_AS, "AS"); + $this->addKeyword(self::T_ASC, "ASC"); + $this->addKeyword(self::T_AVG, "AVG"); + $this->addKeyword(self::T_BETWEEN, "BETWEEN"); + $this->addKeyword(self::T_BY, "BY"); + $this->addKeyword(self::T_COMMA, ","); + $this->addKeyword(self::T_COUNT, "COUNT"); + $this->addKeyword(self::T_DELETE, "DELETE"); + $this->addKeyword(self::T_DESC, "DESC"); + $this->addKeyword(self::T_DISTINCT, "DISTINCT"); + $this->addKeyword(self::T_DOT, "."); + $this->addKeyword(self::T_ESCAPE, "ESPACE"); + $this->addKeyword(self::T_EXISTS, "EXISTS"); + $this->addKeyword(self::T_FALSE, "FALSE"); + $this->addKeyword(self::T_FROM, "FROM"); + $this->addKeyword(self::T_GROUP, "GROUP"); + $this->addKeyword(self::T_HAVING, "HAVING"); + $this->addKeyword(self::T_IN, "IN"); + $this->addKeyword(self::T_INDEX, "INDEX"); + $this->addKeyword(self::T_INNER, "INNER"); + $this->addKeyword(self::T_IS, "IS"); + $this->addKeyword(self::T_JOIN, "JOIN"); + $this->addKeyword(self::T_LEFT, "LEFT"); + $this->addKeyword(self::T_LIKE, "LIKE"); + $this->addKeyword(self::T_LIMIT, "LIMIT"); + $this->addKeyword(self::T_MAX, "MAX"); + $this->addKeyword(self::T_MIN, "MIN"); + $this->addKeyword(self::T_MOD, "MOD"); + $this->addKeyword(self::T_NOT, "NOT"); + $this->addKeyword(self::T_NULL, "NULL"); + $this->addKeyword(self::T_OFFSET, "OFFSET"); + $this->addKeyword(self::T_ON, "ON"); + $this->addKeyword(self::T_OR, "OR"); + $this->addKeyword(self::T_ORDER, "ORDER"); + $this->addKeyword(self::T_OUTER, "OUTER"); + $this->addKeyword(self::T_SELECT, "SELECT"); + $this->addKeyword(self::T_SET, "SET"); + $this->addKeyword(self::T_SIZE, "SIZE"); + $this->addKeyword(self::T_SOME, "SOME"); + $this->addKeyword(self::T_SUM, "SUM"); + $this->addKeyword(self::T_TRUE, "TRUE"); + $this->addKeyword(self::T_UPDATE, "UPDATE"); + $this->addKeyword(self::T_WHERE, "WHERE"); + $this->addKeyword(self::T_WITH, "WITH"); + } return isset($this->_keywordsTable[$token]) ? $this->_keywordsTable[$token] : (is_string($token) ? $token : ''); diff --git a/tests/Orm/Query/SelectSqlGenerationTest.php b/tests/Orm/Query/SelectSqlGenerationTest.php index 55b0f3a79..500e119ba 100755 --- a/tests/Orm/Query/SelectSqlGenerationTest.php +++ b/tests/Orm/Query/SelectSqlGenerationTest.php @@ -50,6 +50,7 @@ class Orm_Query_SelectSqlGenerationTest extends Doctrine_OrmTestCase parent::assertEquals($sqlToBeConfirmed, $query->getSql()); $query->free(); } catch (Doctrine_Exception $e) { + echo $e->getMessage(); echo $e->getTraceAsString(); die(); $this->fail($e->getMessage()); } @@ -112,7 +113,7 @@ class Orm_Query_SelectSqlGenerationTest extends Doctrine_OrmTestCase public function testWhereClauseInSelect() { $this->assertSqlGeneration( - 'select u from ForumUser u where u.id = ?', + 'select u from ForumUser u where u.id = ?1', 'SELECT fu.id AS fu__id, fu.username AS fu__username FROM ForumUser fu WHERE fu.id = ?' ); }